Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Zwinkau
libfirm
Commits
0d56c991
Commit
0d56c991
authored
Oct 04, 2011
by
yb9976
Browse files
Lower double word builtins.
parent
dcab4eed
Changes
1
Hide whitespace changes
Inline
Side-by-side
ir/lower/lower_dw.c
View file @
0d56c991
...
...
@@ -31,9 +31,11 @@
#include
<stdbool.h>
#include
<assert.h>
#include
"be.h"
#include
"error.h"
#include
"lowering.h"
#include
"irnode_t.h"
#include
"irnodeset.h"
#include
"irgraph_t.h"
#include
"irmode_t.h"
#include
"iropt_t.h"
...
...
@@ -46,6 +48,7 @@
#include
"irgwalk.h"
#include
"ircons.h"
#include
"irflag.h"
#include
"iroptimize.h"
#include
"irtools.h"
#include
"debug.h"
#include
"set.h"
...
...
@@ -65,9 +68,15 @@ static set *conv_types;
/** A map from a method type to its lowered type. */
static
pmap
*
lowered_type
;
/** A map from a builtin type to its lower and higher type. */
static
pmap
*
lowered_builtin_type_high
;
static
pmap
*
lowered_builtin_type_low
;
/** The types for the binop and unop intrinsics. */
static
ir_type
*
binop_tp_u
,
*
binop_tp_s
,
*
unop_tp_u
,
*
unop_tp_s
,
*
tp_s
,
*
tp_u
;
static
ir_nodeset_t
created_mux_nodes
;
/** the debug handle */
DEBUG_ONLY
(
static
firm_dbg_module_t
*
dbg
=
NULL
;)
...
...
@@ -2315,6 +2324,337 @@ static void lower_ASM(ir_node *asmn, ir_mode *mode)
}
}
/**
* Lower the builtin type to its higher part.
*
* @param mtp the builtin type to lower
*
* @return the lowered type
*/
static
ir_type
*
lower_Builtin_type_high
(
ir_type
*
mtp
)
{
ir_type
*
res
;
size_t
i
;
size_t
n_params
;
size_t
n_res
;
bool
must_be_lowered
;
res
=
(
ir_type
*
)
pmap_get
(
lowered_builtin_type_high
,
mtp
);
if
(
res
!=
NULL
)
return
res
;
n_params
=
get_method_n_params
(
mtp
);
n_res
=
get_method_n_ress
(
mtp
);
must_be_lowered
=
false
;
/* count new number of params */
for
(
i
=
n_params
;
i
>
0
;)
{
ir_type
*
tp
=
get_method_param_type
(
mtp
,
--
i
);
if
(
is_Primitive_type
(
tp
))
{
ir_mode
*
mode
=
get_type_mode
(
tp
);
if
(
mode
==
env
->
high_signed
||
mode
==
env
->
high_unsigned
)
{
must_be_lowered
=
true
;
break
;
}
}
}
if
(
!
must_be_lowered
)
{
set_type_link
(
mtp
,
NULL
);
return
mtp
;
}
res
=
new_d_type_method
(
n_params
,
n_res
,
get_type_dbg_info
(
mtp
));
/* set param types and result types */
for
(
i
=
0
;
i
<
n_params
;
++
i
)
{
ir_type
*
tp
=
get_method_param_type
(
mtp
,
i
);
if
(
is_Primitive_type
(
tp
))
{
ir_mode
*
mode
=
get_type_mode
(
tp
);
if
(
mode
==
env
->
high_signed
)
{
if
(
env
->
params
->
little_endian
)
{
set_method_param_type
(
res
,
i
,
tp_u
);
}
else
{
set_method_param_type
(
res
,
i
,
tp_s
);
}
}
else
if
(
mode
==
env
->
high_unsigned
)
{
set_method_param_type
(
res
,
i
,
tp_u
);
}
else
{
set_method_param_type
(
res
,
i
,
tp
);
}
}
else
{
set_method_param_type
(
res
,
i
,
tp
);
}
}
for
(
i
=
n_res
=
0
;
i
<
n_res
;
++
i
)
{
ir_type
*
tp
=
get_method_res_type
(
mtp
,
i
);
set_method_res_type
(
res
,
i
,
tp
);
}
set_method_variadicity
(
res
,
get_method_variadicity
(
mtp
));
set_method_calling_convention
(
res
,
get_method_calling_convention
(
mtp
));
set_method_additional_properties
(
res
,
get_method_additional_properties
(
mtp
));
pmap_insert
(
lowered_builtin_type_high
,
mtp
,
res
);
return
res
;
}
/**
* Lower the builtin type to its lower part.
*
* @param mtp the builtin type to lower
*
* @return the lowered type
*/
static
ir_type
*
lower_Builtin_type_low
(
ir_type
*
mtp
)
{
ir_type
*
res
;
size_t
i
;
size_t
n_params
;
size_t
n_ress
;
bool
must_be_lowered
;
res
=
(
ir_type
*
)
pmap_get
(
lowered_builtin_type_low
,
mtp
);
if
(
res
!=
NULL
)
return
res
;
n_params
=
get_method_n_params
(
mtp
);
n_ress
=
get_method_n_ress
(
mtp
);
must_be_lowered
=
false
;
/* count new number of params */
for
(
i
=
n_params
;
i
>
0
;)
{
ir_type
*
tp
=
get_method_param_type
(
mtp
,
--
i
);
if
(
is_Primitive_type
(
tp
))
{
ir_mode
*
mode
=
get_type_mode
(
tp
);
if
(
mode
==
env
->
high_signed
||
mode
==
env
->
high_unsigned
)
{
must_be_lowered
=
true
;
break
;
}
}
}
/* count new number of results */
for
(
i
=
n_ress
;
i
>
0
;)
{
ir_type
*
tp
=
get_method_res_type
(
mtp
,
--
i
);
if
(
is_Primitive_type
(
tp
))
{
ir_mode
*
mode
=
get_type_mode
(
tp
);
if
(
mode
==
env
->
high_signed
||
mode
==
env
->
high_unsigned
)
{
must_be_lowered
=
true
;
}
}
}
if
(
!
must_be_lowered
)
{
set_type_link
(
mtp
,
NULL
);
return
mtp
;
}
res
=
new_d_type_method
(
n_params
,
n_ress
,
get_type_dbg_info
(
mtp
));
/* set param types and result types */
for
(
i
=
0
;
i
<
n_params
;
++
i
)
{
ir_type
*
tp
=
get_method_param_type
(
mtp
,
i
);
if
(
is_Primitive_type
(
tp
))
{
ir_mode
*
mode
=
get_type_mode
(
tp
);
if
(
mode
==
env
->
high_signed
)
{
if
(
env
->
params
->
little_endian
)
{
set_method_param_type
(
res
,
i
,
tp_s
);
}
else
{
set_method_param_type
(
res
,
i
,
tp_u
);
}
}
else
if
(
mode
==
env
->
high_unsigned
)
{
set_method_param_type
(
res
,
i
,
tp_u
);
}
else
{
set_method_param_type
(
res
,
i
,
tp
);
}
}
else
{
set_method_param_type
(
res
,
i
,
tp
);
}
}
for
(
i
=
0
;
i
<
n_ress
;
++
i
)
{
ir_type
*
tp
=
get_method_res_type
(
mtp
,
i
);
set_method_res_type
(
res
,
i
,
tp
);
}
set_method_variadicity
(
res
,
get_method_variadicity
(
mtp
));
set_method_calling_convention
(
res
,
get_method_calling_convention
(
mtp
));
set_method_additional_properties
(
res
,
get_method_additional_properties
(
mtp
));
pmap_insert
(
lowered_builtin_type_low
,
mtp
,
res
);
return
res
;
}
/**
* Lower double word builtins.
*/
static
void
lower_Builtin
(
ir_node
*
builtin
,
ir_mode
*
mode
)
{
ir_builtin_kind
kind
=
get_Builtin_kind
(
builtin
);
ir_node
*
operand
;
ir_mode
*
operand_mode
;
switch
(
kind
)
{
case
ir_bk_trap
:
case
ir_bk_debugbreak
:
case
ir_bk_return_address
:
case
ir_bk_frame_address
:
case
ir_bk_prefetch
:
case
ir_bk_bswap
:
case
ir_bk_inport
:
case
ir_bk_outport
:
case
ir_bk_inner_trampoline
:
/* Nothing to do. */
return
;
case
ir_bk_ffs
:
case
ir_bk_clz
:
case
ir_bk_ctz
:
case
ir_bk_popcount
:
case
ir_bk_parity
:
break
;
default:
panic
(
"unknown builtin"
);
}
operand
=
get_Builtin_param
(
builtin
,
0
);
operand_mode
=
get_irn_mode
(
operand
);
if
(
operand_mode
!=
env
->
high_signed
&&
operand_mode
!=
env
->
high_unsigned
)
return
;
arch_allow_ifconv_func
allow_ifconv
=
be_get_backend_param
()
->
allow_ifconv
;
int
arity
=
get_irn_arity
(
builtin
);
dbg_info
*
dbgi
=
get_irn_dbg_info
(
builtin
);
ir_graph
*
irg
=
get_irn_irg
(
builtin
);
ir_type
*
type
=
get_Builtin_type
(
builtin
);
ir_type
*
lowered_type_high
=
lower_Builtin_type_high
(
type
);
ir_type
*
lowered_type_low
=
lower_Builtin_type_low
(
type
);
ir_node
*
block
=
get_nodes_block
(
builtin
);
ir_node
*
mem
=
get_Builtin_mem
(
builtin
);
ir_node
*
res
;
assert
(
is_NoMem
(
mem
));
assert
(
arity
==
2
);
switch
(
kind
)
{
case
ir_bk_ffs
:
{
const
lower64_entry_t
*
entry
=
get_node_entry
(
operand
);
ir_node
*
in_high
[
1
]
=
{
entry
->
high_word
};
ir_node
*
in_low
[
1
]
=
{
entry
->
low_word
};
ir_node
*
number_of_bits
=
new_r_Const_long
(
irg
,
mode_Is
,
get_mode_size_bits
(
env
->
low_unsigned
));
ir_node
*
zero_signed
=
new_rd_Const
(
dbgi
,
irg
,
get_mode_null
(
mode_Is
));
ir_node
*
zero_unsigned
=
new_rd_Const
(
dbgi
,
irg
,
get_mode_null
(
mode_Iu
));
ir_node
*
cmp_low
=
new_rd_Cmp
(
dbgi
,
block
,
entry
->
low_word
,
zero_unsigned
,
ir_relation_equal
);
ir_node
*
cmp_high
=
new_rd_Cmp
(
dbgi
,
block
,
entry
->
high_word
,
zero_unsigned
,
ir_relation_equal
);
ir_node
*
ffs_high
=
new_rd_Builtin
(
dbgi
,
block
,
mem
,
1
,
in_high
,
kind
,
lowered_type_high
);
ir_node
*
high_proj
=
new_r_Proj
(
ffs_high
,
mode_Is
,
pn_Builtin_1_result
);
ir_node
*
high
=
new_rd_Add
(
dbgi
,
block
,
high_proj
,
number_of_bits
,
mode_Is
);
ir_node
*
ffs_low
=
new_rd_Builtin
(
dbgi
,
block
,
mem
,
1
,
in_low
,
kind
,
lowered_type_low
);
ir_node
*
low
=
new_r_Proj
(
ffs_low
,
mode_Is
,
pn_Builtin_1_result
);
ir_node
*
mux_high
=
new_rd_Mux
(
dbgi
,
block
,
cmp_high
,
high
,
zero_signed
,
mode_Is
);
if
(
!
allow_ifconv
(
cmp_high
,
high
,
zero_signed
))
ir_nodeset_insert
(
&
created_mux_nodes
,
mux_high
);
res
=
new_rd_Mux
(
dbgi
,
block
,
cmp_low
,
low
,
mux_high
,
mode_Is
);
if
(
!
allow_ifconv
(
cmp_low
,
low
,
mux_high
))
ir_nodeset_insert
(
&
created_mux_nodes
,
res
);
}
break
;
case
ir_bk_clz
:
{
const
lower64_entry_t
*
entry
=
get_node_entry
(
operand
);
ir_node
*
in_high
[
1
]
=
{
entry
->
high_word
};
ir_node
*
in_low
[
1
]
=
{
entry
->
low_word
};
ir_node
*
number_of_bits
=
new_r_Const_long
(
irg
,
mode_Is
,
get_mode_size_bits
(
mode
));
ir_node
*
zero_unsigned
=
new_rd_Const
(
dbgi
,
irg
,
get_mode_null
(
mode_Iu
));
ir_node
*
cmp_high
=
new_rd_Cmp
(
dbgi
,
block
,
entry
->
high_word
,
zero_unsigned
,
ir_relation_equal
);
ir_node
*
clz_high
=
new_rd_Builtin
(
dbgi
,
block
,
mem
,
1
,
in_high
,
kind
,
lowered_type_high
);
ir_node
*
high
=
new_r_Proj
(
clz_high
,
mode_Is
,
pn_Builtin_1_result
);
ir_node
*
clz_low
=
new_rd_Builtin
(
dbgi
,
block
,
mem
,
1
,
in_low
,
kind
,
lowered_type_low
);
ir_node
*
low_proj
=
new_r_Proj
(
clz_low
,
mode_Is
,
pn_Builtin_1_result
);
ir_node
*
low
=
new_rd_Add
(
dbgi
,
block
,
low_proj
,
number_of_bits
,
mode_Is
);
res
=
new_rd_Mux
(
dbgi
,
block
,
cmp_high
,
high
,
low
,
mode_Is
);
if
(
!
allow_ifconv
(
cmp_high
,
high
,
low
))
ir_nodeset_insert
(
&
created_mux_nodes
,
res
);
}
break
;
case
ir_bk_ctz
:
{
const
lower64_entry_t
*
entry
=
get_node_entry
(
operand
);
ir_node
*
in_high
[
1
]
=
{
entry
->
high_word
};
ir_node
*
in_low
[
1
]
=
{
entry
->
low_word
};
ir_node
*
number_of_bits
=
new_r_Const_long
(
irg
,
mode_Is
,
get_mode_size_bits
(
env
->
low_unsigned
));
ir_node
*
zero_unsigned
=
new_rd_Const
(
dbgi
,
irg
,
get_mode_null
(
mode_Iu
));
ir_node
*
cmp_low
=
new_rd_Cmp
(
dbgi
,
block
,
entry
->
low_word
,
zero_unsigned
,
ir_relation_equal
);
ir_node
*
ffs_high
=
new_rd_Builtin
(
dbgi
,
block
,
mem
,
1
,
in_high
,
kind
,
lowered_type_high
);
ir_node
*
high_proj
=
new_r_Proj
(
ffs_high
,
mode_Is
,
pn_Builtin_1_result
);
ir_node
*
high
=
new_rd_Add
(
dbgi
,
block
,
high_proj
,
number_of_bits
,
mode_Is
);
ir_node
*
ffs_low
=
new_rd_Builtin
(
dbgi
,
block
,
mem
,
1
,
in_low
,
kind
,
lowered_type_low
);
ir_node
*
low
=
new_r_Proj
(
ffs_low
,
mode_Is
,
pn_Builtin_1_result
);
res
=
new_rd_Mux
(
dbgi
,
block
,
cmp_low
,
low
,
high
,
mode_Is
);
if
(
!
allow_ifconv
(
cmp_low
,
low
,
high
))
ir_nodeset_insert
(
&
created_mux_nodes
,
res
);
}
break
;
case
ir_bk_popcount
:
{
const
lower64_entry_t
*
entry
=
get_node_entry
(
operand
);
ir_node
*
in_high
[
1
]
=
{
entry
->
high_word
};
ir_node
*
in_low
[
1
]
=
{
entry
->
low_word
};
ir_node
*
popcount_high
=
new_rd_Builtin
(
dbgi
,
block
,
mem
,
1
,
in_high
,
kind
,
lowered_type_high
);
ir_node
*
popcount_low
=
new_rd_Builtin
(
dbgi
,
block
,
mem
,
1
,
in_low
,
kind
,
lowered_type_low
);
ir_node
*
high
=
new_r_Proj
(
popcount_high
,
mode_Is
,
pn_Builtin_1_result
);
ir_node
*
low
=
new_r_Proj
(
popcount_low
,
mode_Is
,
pn_Builtin_1_result
);
res
=
new_rd_Add
(
dbgi
,
block
,
high
,
low
,
mode_Is
);
}
break
;
case
ir_bk_parity
:
{
const
lower64_entry_t
*
entry
=
get_node_entry
(
operand
);
ir_node
*
in_high
[
1
]
=
{
entry
->
high_word
};
ir_node
*
in_low
[
1
]
=
{
entry
->
low_word
};
ir_node
*
parity_high
;
ir_node
*
parity_low
;
ir_node
*
high
;
ir_node
*
low
;
assert
(
arity
==
2
);
parity_high
=
new_rd_Builtin
(
dbgi
,
block
,
mem
,
1
,
in_high
,
kind
,
lowered_type_high
);
high
=
new_r_Proj
(
parity_high
,
mode_Is
,
pn_Builtin_1_result
);
parity_low
=
new_rd_Builtin
(
dbgi
,
block
,
mem
,
1
,
in_low
,
kind
,
lowered_type_low
);
low
=
new_r_Proj
(
parity_low
,
mode_Is
,
pn_Builtin_1_result
);
res
=
new_rd_Eor
(
dbgi
,
block
,
high
,
low
,
mode_Is
);
}
break
;
default:
panic
(
"unexpected builtin"
);
}
turn_into_tuple
(
builtin
,
2
);
set_irn_n
(
builtin
,
pn_Builtin_M
,
mem
);
set_irn_n
(
builtin
,
pn_Builtin_1_result
,
res
);
}
/**
* check for opcodes that must always be lowered.
*/
...
...
@@ -2322,6 +2662,7 @@ static bool always_lower(unsigned code)
{
switch
(
code
)
{
case
iro_ASM
:
case
iro_Builtin
:
case
iro_Proj
:
case
iro_Start
:
case
iro_Call
:
...
...
@@ -2611,6 +2952,7 @@ void ir_prepare_dw_lowering(const lwrdw_param_t *new_param)
ir_register_dw_lower_function
(
op_Add
,
lower_binop
);
ir_register_dw_lower_function
(
op_And
,
lower_And
);
ir_register_dw_lower_function
(
op_Bad
,
lower_Bad
);
ir_register_dw_lower_function
(
op_Builtin
,
lower_Builtin
);
ir_register_dw_lower_function
(
op_Call
,
lower_Call
);
ir_register_dw_lower_function
(
op_Cmp
,
lower_Cmp
);
ir_register_dw_lower_function
(
op_Cond
,
lower_Cond
);
...
...
@@ -2635,6 +2977,14 @@ void ir_prepare_dw_lowering(const lwrdw_param_t *new_param)
ir_register_dw_lower_function
(
op_Unknown
,
lower_Unknown
);
}
/**
* Callback to lower only the Mux nodes we created.
*/
static
int
lower_mux_cb
(
ir_node
*
mux
)
{
return
ir_nodeset_contains
(
&
created_mux_nodes
,
mux
);
}
/*
* Do the lowering.
*/
...
...
@@ -2656,6 +3006,10 @@ void ir_lower_dw_ops(void)
conv_types
=
new_set
(
cmp_conv_tp
,
16
);
if
(
!
lowered_type
)
lowered_type
=
pmap_create
();
if
(
!
lowered_builtin_type_low
)
lowered_builtin_type_low
=
pmap_create
();
if
(
!
lowered_builtin_type_high
)
lowered_builtin_type_high
=
pmap_create
();
/* create a primitive unsigned and signed type */
if
(
!
tp_u
)
...
...
@@ -2723,7 +3077,15 @@ void ir_lower_dw_ops(void)
/* transform all graphs */
for
(
i
=
0
,
n
=
get_irp_n_irgs
();
i
<
n
;
++
i
)
{
ir_graph
*
irg
=
get_irp_irg
(
i
);
ir_nodeset_init
(
&
created_mux_nodes
);
lower_irg
(
irg
);
if
(
ir_nodeset_size
(
&
created_mux_nodes
)
>
0
)
lower_mux
(
irg
,
lower_mux_cb
);
ir_nodeset_destroy
(
&
created_mux_nodes
);
}
irp_free_resources
(
irp
,
IRP_RESOURCE_TYPE_LINK
);
del_pdeq
(
lenv
.
waitq
);
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment