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
d9b6f3a9
Commit
d9b6f3a9
authored
Jun 28, 2007
by
Matthias Braun
Browse files
rewrite and improve Cond transformation
[r14821]
parent
95217dbe
Changes
3
Hide whitespace changes
Inline
Side-by-side
ir/be/ia32/ia32_emitter.c
View file @
d9b6f3a9
...
...
@@ -836,19 +836,10 @@ void emit_ia32_CondJmp(ia32_emit_env_t *env, const ir_node *node) {
*/
static
void
TestJmp_emitter
(
ia32_emit_env_t
*
env
,
const
ir_node
*
node
)
{
if
(
is_ia32_ImmSymConst
(
node
)
||
is_ia32_ImmConst
(
node
))
{
be_emit_cstring
(
env
,
"
\t
test "
);
ia32_emit_immediate
(
env
,
node
);
be_emit_cstring
(
env
,
", "
);
ia32_emit_source_register
(
env
,
node
,
0
);
be_emit_finish_line_gas
(
env
,
node
);
}
else
{
be_emit_cstring
(
env
,
"
\t
test "
);
ia32_emit_source_register
(
env
,
node
,
1
);
be_emit_cstring
(
env
,
", "
);
ia32_emit_source_register
(
env
,
node
,
0
);
be_emit_finish_line_gas
(
env
,
node
);
}
be_emit_cstring
(
env
,
"
\t
test "
);
ia32_emit_binop
(
env
,
node
);
be_emit_finish_line_gas
(
env
,
node
);
finish_CondJmp
(
env
,
node
,
mode_Iu
,
get_ia32_pncode
(
node
));
}
...
...
ir/be/ia32/ia32_spec.pl
View file @
d9b6f3a9
...
...
@@ -771,8 +771,12 @@ Not => {
CondJmp
=>
{
state
=>
"
pinned
",
op_flags
=>
"
L|X|Y
",
reg_req
=>
{
in
=>
[
"
gp
",
"
gp
",
"
gp
",
"
gp
",
"
none
"
],
out
=>
[
"
none
",
"
none
"]
},
reg_req
=>
{
in
=>
[
"
gp
",
"
gp
",
"
gp
",
"
gp
",
"
none
"
],
out
=>
[
"
none
",
"
none
"]
},
ins
=>
[
"
base
",
"
index
",
"
left
",
"
right
",
"
mem
"
],
outs
=>
[
"
false
",
"
true
"
],
attr
=>
"
long pnc
",
init_attr
=>
"
attr->pn_code = pnc;
",
latency
=>
3
,
units
=>
[
"
BRANCH
"
],
},
...
...
@@ -780,8 +784,12 @@ CondJmp => {
TestJmp
=>
{
state
=>
"
pinned
",
op_flags
=>
"
L|X|Y
",
reg_req
=>
{
in
=>
[
"
gp
",
"
gp
"
],
out
=>
[
"
none
",
"
none
"
]
},
reg_req
=>
{
in
=>
[
"
gp
",
"
gp
",
"
gp
",
"
gp
",
"
none
"
],
out
=>
[
"
none
",
"
none
"
]
},
ins
=>
[
"
base
",
"
index
",
"
left
",
"
right
",
"
mem
"
],
outs
=>
[
"
false
",
"
true
"
],
attr
=>
"
long pnc
",
init_attr
=>
"
attr->pn_code = pnc;
",
latency
=>
3
,
units
=>
[
"
BRANCH
"
],
},
...
...
@@ -807,6 +815,7 @@ SwitchJmp => {
reg_req
=>
{
in
=>
[
"
gp
"
],
out
=>
[
"
none
"
]
},
latency
=>
3
,
units
=>
[
"
BRANCH
"
],
mode
=>
"
mode_T
",
},
Const
=>
{
...
...
ir/be/ia32/ia32_transform.c
View file @
d9b6f3a9
...
...
@@ -1753,7 +1753,97 @@ static ir_node *gen_Store(ir_node *node) {
return
new_op
;
}
static
ir_node
*
try_create_TestJmp
(
ir_node
*
node
,
long
pnc
)
{
ir_node
*
cmp_a
=
get_Cmp_left
(
node
);
ir_node
*
new_cmp_a
;
ir_node
*
cmp_b
=
get_Cmp_right
(
node
);
ir_node
*
new_cmp_b
;
ir_node
*
and_left
;
ir_node
*
and_right
;
ir_node
*
res
;
ir_node
*
block
;
ir_node
*
noreg
;
ir_node
*
nomem
;
dbg_info
*
dbgi
;
tarval
*
tv
;
if
(
pnc
!=
pn_Cmp_Eq
&&
pnc
!=
pn_Cmp_Lg
)
return
NULL
;
if
(
!
is_Const
(
cmp_b
))
return
NULL
;
tv
=
get_Const_tarval
(
cmp_b
);
if
(
!
tarval_is_null
(
tv
))
return
NULL
;
if
(
!
is_And
(
cmp_a
))
return
NULL
;
/* only fold if we're the only user of the And (it's not 100% clear that
* this is better, as we could have a series of Conds as users...)
*/
if
(
get_irn_n_edges
(
cmp_a
)
>
1
)
return
NULL
;
and_left
=
get_And_left
(
cmp_a
);
and_right
=
get_And_right
(
cmp_a
);
if
(
!
is_Const
(
and_right
))
return
NULL
;
dbgi
=
get_irn_dbg_info
(
node
);
block
=
be_transform_node
(
get_nodes_block
(
node
));
noreg
=
ia32_new_NoReg_gp
(
env_cg
);
nomem
=
new_NoMem
();
new_cmp_a
=
be_transform_node
(
and_left
);
new_cmp_b
=
try_create_Immediate
(
and_right
,
0
);
if
(
new_cmp_b
==
NULL
)
panic
(
"couldn't create immediate for TestJmp"
);
res
=
new_rd_ia32_TestJmp
(
dbgi
,
current_ir_graph
,
block
,
noreg
,
noreg
,
new_cmp_a
,
new_cmp_b
,
nomem
,
pnc
);
SET_IA32_ORIG_NODE
(
res
,
ia32_get_old_node_name
(
env_cg
,
node
));
return
res
;
}
static
ir_node
*
create_Switch
(
ir_node
*
node
)
{
ir_graph
*
irg
=
current_ir_graph
;
dbg_info
*
dbgi
=
get_irn_dbg_info
(
node
);
ir_node
*
block
=
be_transform_node
(
get_nodes_block
(
node
));
ir_node
*
sel
=
get_Cond_selector
(
node
);
ir_node
*
new_sel
=
be_transform_node
(
sel
);
ir_node
*
res
;
int
switch_min
=
INT_MAX
;
const
ir_edge_t
*
edge
;
/* determine the smallest switch case value */
foreach_out_edge
(
node
,
edge
)
{
ir_node
*
proj
=
get_edge_src_irn
(
edge
);
int
pn
=
get_Proj_proj
(
proj
);
if
(
pn
<
switch_min
)
switch_min
=
pn
;
}
if
(
switch_min
!=
0
)
{
ir_node
*
noreg
=
ia32_new_NoReg_gp
(
env_cg
);
/* if smallest switch case is not 0 we need an additional sub */
new_sel
=
new_rd_ia32_Lea
(
dbgi
,
irg
,
block
,
new_sel
,
noreg
);
add_ia32_am_offs_int
(
new_sel
,
-
switch_min
);
set_ia32_am_flavour
(
new_sel
,
ia32_am_OB
);
set_ia32_op_type
(
new_sel
,
ia32_AddrModeS
);
SET_IA32_ORIG_NODE
(
new_sel
,
ia32_get_old_node_name
(
env_cg
,
node
));
}
res
=
new_rd_ia32_SwitchJmp
(
dbgi
,
irg
,
block
,
new_sel
);
set_ia32_pncode
(
res
,
get_Cond_defaultProj
(
node
));
SET_IA32_ORIG_NODE
(
res
,
ia32_get_old_node_name
(
env_cg
,
node
));
return
res
;
}
/**
* Transforms a Cond -> Proj[b] -> Cmp into a CondJmp, CondJmp_i or TestJmp
...
...
@@ -1768,129 +1858,71 @@ static ir_node *gen_Cond(ir_node *node) {
ir_mode
*
sel_mode
=
get_irn_mode
(
sel
);
ir_node
*
res
=
NULL
;
ir_node
*
noreg
=
ia32_new_NoReg_gp
(
env_cg
);
ir_node
*
cnst
,
*
expr
;
if
(
is_Proj
(
sel
)
&&
sel_mode
==
mode_b
)
{
ir_node
*
pred
=
get_Proj_pred
(
sel
);
ir_node
*
cmp_a
=
get_Cmp_left
(
pred
);
ir_node
*
new_cmp_a
=
be_transform_node
(
cmp_a
);
ir_node
*
cmp_b
=
get_Cmp_right
(
pred
);
ir_node
*
new_cmp_b
=
be_transform_node
(
cmp_b
);
ir_mode
*
cmp_mode
=
get_irn_mode
(
cmp_a
);
ir_node
*
nomem
=
new_NoMem
();
int
pnc
=
get_Proj_proj
(
sel
);
if
(
mode_is_float
(
cmp_mode
)
||
!
mode_is_signed
(
cmp_mode
))
{
pnc
|=
ia32_pn_Cmp_Unsigned
;
}
ir_node
*
cmp
;
ir_node
*
cmp_a
;
ir_node
*
cmp_b
;
ir_node
*
new_cmp_a
;
ir_node
*
new_cmp_b
;
ir_mode
*
cmp_mode
;
ir_node
*
nomem
=
new_NoMem
();
long
pnc
;
/* check if we can use a CondJmp with immediate */
cnst
=
(
env_cg
->
opt
&
IA32_OPT_IMMOPS
)
?
get_immediate_op
(
new_cmp_a
,
new_cmp_b
)
:
NULL
;
expr
=
get_expr_op
(
new_cmp_a
,
new_cmp_b
);
if
(
sel_mode
!=
mode_b
)
{
return
create_Switch
(
node
)
;
}
if
(
cnst
!=
NULL
&&
expr
!=
NULL
)
{
/* immop has to be the right operand, we might need to flip pnc */
if
(
cnst
!=
new_cmp_b
)
{
pnc
=
get_inversed_pnc
(
pnc
);
}
cmp
=
get_Proj_pred
(
sel
);
cmp_a
=
get_Cmp_left
(
cmp
);
cmp_b
=
get_Cmp_right
(
cmp
);
cmp_mode
=
get_irn_mode
(
cmp_a
);
pnc
=
get_Proj_proj
(
sel
);
if
(
mode_is_float
(
cmp_mode
)
||
!
mode_is_signed
(
cmp_mode
))
{
pnc
|=
ia32_pn_Cmp_Unsigned
;
}
if
((
pnc
==
pn_Cmp_Eq
||
pnc
==
pn_Cmp_Lg
)
&&
mode_needs_gp_reg
(
get_irn_mode
(
expr
)))
{
if
(
get_ia32_immop_type
(
cnst
)
==
ia32_ImmConst
&&
classify_tarval
(
get_ia32_Immop_tarval
(
cnst
))
==
TV_CLASSIFY_NULL
)
{
/* a Cmp A =/!= 0 */
ir_node
*
op1
=
expr
;
ir_node
*
op2
=
expr
;
int
is_and
=
0
;
/* check, if expr is an only once used And operation */
if
(
is_ia32_And
(
expr
)
&&
get_irn_n_edges
(
expr
))
{
op1
=
get_irn_n
(
expr
,
2
);
op2
=
get_irn_n
(
expr
,
3
);
is_and
=
(
is_ia32_ImmConst
(
expr
)
||
is_ia32_ImmSymConst
(
expr
));
}
res
=
new_rd_ia32_TestJmp
(
dbgi
,
irg
,
block
,
op1
,
op2
);
set_ia32_pncode
(
res
,
pnc
);
if
(
is_and
)
{
copy_ia32_Immop_attr
(
res
,
expr
);
}
SET_IA32_ORIG_NODE
(
res
,
ia32_get_old_node_name
(
env_cg
,
node
));
return
res
;
}
}
if
(
mode_needs_gp_reg
(
cmp_mode
))
{
res
=
try_create_TestJmp
(
cmp
,
pnc
);
if
(
res
!=
NULL
)
return
res
;
if
(
mode_is_float
(
cmp_mode
))
{
FP_USED
(
env_cg
);
if
(
USE_SSE2
(
env_cg
))
{
res
=
new_rd_ia32_xCondJmp
(
dbgi
,
irg
,
block
,
noreg
,
noreg
,
expr
,
noreg
,
nomem
);
set_ia32_ls_mode
(
res
,
cmp_mode
);
}
else
{
assert
(
0
);
}
}
else
{
assert
(
get_mode_size_bits
(
cmp_mode
)
==
32
);
res
=
new_rd_ia32_CondJmp
(
dbgi
,
irg
,
block
,
noreg
,
noreg
,
expr
,
noreg
,
nomem
);
}
copy_ia32_Immop_attr
(
res
,
cnst
);
}
else
{
ir_mode
*
cmp_mode
=
get_irn_mode
(
cmp_a
);
if
(
mode_is_float
(
cmp_mode
))
{
FP_USED
(
env_cg
);
if
(
USE_SSE2
(
env_cg
))
{
res
=
new_rd_ia32_xCondJmp
(
dbgi
,
irg
,
block
,
noreg
,
noreg
,
cmp_a
,
cmp_b
,
nomem
);
set_ia32_ls_mode
(
res
,
cmp_mode
);
}
else
{
ir_node
*
proj_eax
;
res
=
new_rd_ia32_vfCondJmp
(
dbgi
,
irg
,
block
,
noreg
,
noreg
,
cmp_a
,
cmp_b
,
nomem
);
proj_eax
=
new_r_Proj
(
irg
,
block
,
res
,
mode_Iu
,
pn_ia32_vfCondJmp_temp_reg_eax
);
be_new_Keep
(
&
ia32_reg_classes
[
CLASS_ia32_gp
],
irg
,
block
,
1
,
&
proj_eax
);
}
}
else
{
assert
(
get_mode_size_bits
(
cmp_mode
)
==
32
);
res
=
new_rd_ia32_CondJmp
(
dbgi
,
irg
,
block
,
noreg
,
noreg
,
cmp_a
,
cmp_b
,
nomem
);
set_ia32_commutative
(
res
);
}
new_cmp_b
=
try_create_Immediate
(
cmp_b
,
0
);
if
(
new_cmp_b
==
NULL
)
{
new_cmp_b
=
be_transform_node
(
cmp_b
);
}
set_ia32_pncode
(
res
,
pnc
);
// Matze: disabled for now, because the default collect_spills_walker
// is not able to detect the mode of the spilled value
// moreover, the lea optimize phase freely exchanges left/right
// without updating the pnc
//set_ia32_am_support(res, ia32_am_Source | ia32_am_binary);
new_cmp_a
=
be_transform_node
(
cmp_a
);
}
else
{
new_cmp_a
=
be_transform_node
(
cmp_a
);
new_cmp_b
=
be_transform_node
(
cmp_b
);
}
else
{
/* determine the smallest switch case value */
ir_node
*
new_sel
=
be_transform_node
(
sel
);
int
switch_min
=
INT_MAX
;
const
ir_edge_t
*
edge
;
foreach_out_edge
(
node
,
edge
)
{
int
pn
=
get_Proj_proj
(
get_edge_src_irn
(
edge
));
switch_min
=
pn
<
switch_min
?
pn
:
switch_min
;
}
if
(
switch_min
)
{
/* if smallest switch case is not 0 we need an additional sub */
res
=
new_rd_ia32_Lea
(
dbgi
,
irg
,
block
,
new_sel
,
noreg
);
SET_IA32_ORIG_NODE
(
res
,
ia32_get_old_node_name
(
env_cg
,
node
));
add_ia32_am_offs_int
(
res
,
-
switch_min
);
set_ia32_am_flavour
(
res
,
ia32_am_OB
);
set_ia32_op_type
(
res
,
ia32_AddrModeS
);
if
(
mode_is_float
(
cmp_mode
))
{
FP_USED
(
env_cg
);
if
(
USE_SSE2
(
env_cg
))
{
res
=
new_rd_ia32_xCondJmp
(
dbgi
,
irg
,
block
,
noreg
,
noreg
,
cmp_a
,
cmp_b
,
nomem
);
set_ia32_pncode
(
res
,
pnc
);
set_ia32_ls_mode
(
res
,
cmp_mode
);
}
else
{
ir_node
*
proj_eax
;
res
=
new_rd_ia32_vfCondJmp
(
dbgi
,
irg
,
block
,
noreg
,
noreg
,
cmp_a
,
cmp_b
,
nomem
);
set_ia32_pncode
(
res
,
pnc
);
proj_eax
=
new_r_Proj
(
irg
,
block
,
res
,
mode_Iu
,
pn_ia32_vfCondJmp_temp_reg_eax
);
be_new_Keep
(
&
ia32_reg_classes
[
CLASS_ia32_gp
],
irg
,
block
,
1
,
&
proj_eax
);
}
res
=
new_rd_ia32_SwitchJmp
(
dbgi
,
irg
,
block
,
switch_min
?
res
:
new_sel
,
mode_T
);
set_ia32_pncode
(
res
,
get_Cond_defaultProj
(
node
));
}
else
{
assert
(
get_mode_size_bits
(
cmp_mode
)
==
32
);
res
=
new_rd_ia32_CondJmp
(
dbgi
,
irg
,
block
,
noreg
,
noreg
,
new_cmp_a
,
new_cmp_b
,
nomem
,
pnc
);
set_ia32_commutative
(
res
);
}
// Matze: disabled for now, because the default collect_spills_walker
// is not able to detect the mode of the spilled value
// moreover, the lea optimize phase freely exchanges left/right
// without updating the pnc
//set_ia32_am_support(res, ia32_am_Source | ia32_am_binary);
SET_IA32_ORIG_NODE
(
res
,
ia32_get_old_node_name
(
env_cg
,
node
));
return
res
;
}
...
...
Write
Preview
Markdown
is supported
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