Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Zwinkau
libfirm
Commits
f7aaa97c
Commit
f7aaa97c
authored
Aug 28, 2014
by
Andreas Fried
Browse files
Optimize 64-bit Add/Sub which will certainly carry.
parent
a443f204
Changes
1
Hide whitespace changes
Inline
Side-by-side
ir/be/ia32/ia32_intrinsics.c
View file @
f7aaa97c
...
...
@@ -28,6 +28,12 @@
#include
"gen_ia32_regalloc_if.h"
#include
"begnuas.h"
typedef
enum
{
no_carry
=
0
,
can_carry
,
must_carry
}
carry_result
;
static
ir_tarval
*
bitinfo_max
(
bitinfo
*
info
)
{
ir_tarval
*
z
=
info
->
z
;
...
...
@@ -50,8 +56,10 @@ static ir_tarval *bitinfo_min(bitinfo *info)
return
tarval_or
(
o
,
tarval_and
(
z
,
min
));
}
static
bool
lower_add_
can_
carry
(
ir_node
*
left
,
ir_node
*
right
,
ir_mode
*
mode
)
static
carry_result
lower_add_carry
(
ir_node
*
left
,
ir_node
*
right
,
ir_mode
*
mode
)
{
assert
(
!
mode_is_signed
(
mode
));
bitinfo
*
bi_left
=
get_bitinfo
(
left
);
if
(
!
bi_left
)
{
return
true
;
...
...
@@ -61,18 +69,20 @@ static bool lower_add_can_carry(ir_node *left, ir_node *right, ir_mode *mode)
// the other
assert
(
bi_right
);
ir_tarval
*
lmin
=
tarval_convert_to
(
bitinfo_min
(
bi_left
),
mode
);
ir_tarval
*
rmin
=
tarval_convert_to
(
bitinfo_min
(
bi_right
),
mode
);
ir_tarval
*
lmax
=
tarval_convert_to
(
bitinfo_max
(
bi_left
),
mode
);
ir_tarval
*
rmax
=
tarval_convert_to
(
bitinfo_max
(
bi_right
),
mode
);
bool
result
=
false
;
ir_tarval
*
lmin
=
tarval_convert_to
(
bitinfo_min
(
bi_left
),
mode
);
ir_tarval
*
rmin
=
tarval_convert_to
(
bitinfo_min
(
bi_right
),
mode
);
ir_tarval
*
lmax
=
tarval_convert_to
(
bitinfo_max
(
bi_left
),
mode
);
ir_tarval
*
rmax
=
tarval_convert_to
(
bitinfo_max
(
bi_right
),
mode
);
carry_result
result
=
no_carry
;
tarval_int_overflow_mode_t
ofm
=
tarval_get_integer_overflow_mode
();
tarval_set_integer_overflow_mode
(
TV_OVERFLOW_BAD
);
if
(
tarval_add
(
lmin
,
rmin
)
==
tarval_bad
||
tarval_add
(
lmax
,
rmax
)
==
tarval_bad
)
{
result
=
true
;
if
(
tarval_add
(
lmax
,
rmax
)
==
tarval_bad
)
{
result
=
can_carry
;
if
(
tarval_add
(
lmin
,
rmin
)
==
tarval_bad
)
{
result
=
must_carry
;
}
}
tarval_set_integer_overflow_mode
(
ofm
);
...
...
@@ -80,8 +90,10 @@ static bool lower_add_can_carry(ir_node *left, ir_node *right, ir_mode *mode)
return
result
;
}
static
bool
lower_sub_
can_
borrow
(
ir_node
*
left
,
ir_node
*
right
,
ir_mode
*
mode
)
static
carry_result
lower_sub_borrow
(
ir_node
*
left
,
ir_node
*
right
,
ir_mode
*
mode
)
{
assert
(
!
mode_is_signed
(
mode
));
bitinfo
*
bi_left
=
get_bitinfo
(
left
);
if
(
!
bi_left
)
{
return
true
;
...
...
@@ -91,18 +103,20 @@ static bool lower_sub_can_borrow(ir_node *left, ir_node *right, ir_mode *mode)
// the other
assert
(
bi_right
);
ir_tarval
*
lmin
=
tarval_convert_to
(
bitinfo_min
(
bi_left
),
mode
);
ir_tarval
*
rmin
=
tarval_convert_to
(
bitinfo_min
(
bi_right
),
mode
);
ir_tarval
*
lmax
=
tarval_convert_to
(
bitinfo_max
(
bi_left
),
mode
);
ir_tarval
*
rmax
=
tarval_convert_to
(
bitinfo_max
(
bi_right
),
mode
);
bool
result
=
false
;
ir_tarval
*
lmin
=
tarval_convert_to
(
bitinfo_min
(
bi_left
),
mode
);
ir_tarval
*
rmin
=
tarval_convert_to
(
bitinfo_min
(
bi_right
),
mode
);
ir_tarval
*
lmax
=
tarval_convert_to
(
bitinfo_max
(
bi_left
),
mode
);
ir_tarval
*
rmax
=
tarval_convert_to
(
bitinfo_max
(
bi_right
),
mode
);
carry_result
result
=
no_carry
;
tarval_int_overflow_mode_t
ofm
=
tarval_get_integer_overflow_mode
();
tarval_set_integer_overflow_mode
(
TV_OVERFLOW_BAD
);
if
(
tarval_sub
(
lmin
,
rmax
,
NULL
)
==
tarval_bad
||
tarval_sub
(
lmax
,
rmin
,
NULL
)
==
tarval_bad
)
{
result
=
true
;
if
(
tarval_sub
(
lmin
,
rmax
,
NULL
)
==
tarval_bad
)
{
result
=
can_carry
;
if
(
tarval_sub
(
lmax
,
rmin
,
NULL
)
==
tarval_bad
)
{
result
=
must_carry
;
}
}
tarval_set_integer_overflow_mode
(
ofm
);
...
...
@@ -112,26 +126,48 @@ static bool lower_sub_can_borrow(ir_node *left, ir_node *right, ir_mode *mode)
/**
* lower 64bit addition: an 32bit add for the lower parts, an add with
* carry for the higher parts.
* carry for the higher parts. If the carry's value is known, fold it
* into the upper add.
*/
static
void
ia32_lower_add64
(
ir_node
*
node
,
ir_mode
*
mode
)
{
dbg_info
*
dbg
=
get_irn_dbg_info
(
node
);
ir_node
*
block
=
get_nodes_block
(
node
);
ir_node
*
left
=
get_Add_left
(
node
);
ir_node
*
right
=
get_Add_right
(
node
);
ir_node
*
left_low
=
get_lowered_low
(
left
);
ir_node
*
left_high
=
get_lowered_high
(
left
);
ir_node
*
right_low
=
get_lowered_low
(
right
);
ir_node
*
right_high
=
get_lowered_high
(
right
);
ir_mode
*
low_mode
=
get_irn_mode
(
left_low
);
dbg_info
*
dbg
=
get_irn_dbg_info
(
node
);
ir_node
*
block
=
get_nodes_block
(
node
);
ir_node
*
left
=
get_Add_left
(
node
);
ir_node
*
right
=
get_Add_right
(
node
);
ir_node
*
left_low
=
get_lowered_low
(
left
);
ir_node
*
left_high
=
get_lowered_high
(
left
);
ir_node
*
right_low
=
get_lowered_low
(
right
);
ir_node
*
right_high
=
get_lowered_high
(
right
);
ir_mode
*
low_mode
=
get_irn_mode
(
left_low
);
ir_mode
*
high_mode
=
get_irn_mode
(
left_high
);
carry_result
cr
=
lower_add_carry
(
left
,
right
,
low_mode
);
assert
(
get_irn_mode
(
left_low
)
==
get_irn_mode
(
right_low
));
assert
(
get_irn_mode
(
left_high
)
==
get_irn_mode
(
right_high
));
if
(
!
lower_add_can_carry
(
left
,
right
,
low_mode
)
)
{
if
(
cr
==
no_carry
)
{
ir_node
*
add_low
=
new_rd_Add
(
dbg
,
block
,
left_low
,
right_low
,
low_mode
);
ir_node
*
add_high
=
new_rd_Add
(
dbg
,
block
,
left_high
,
right_high
,
get_irn_mode
(
left_high
));
ir_node
*
add_high
=
new_rd_Add
(
dbg
,
block
,
left_high
,
right_high
,
high_mode
);
ir_set_dw_lowered
(
node
,
add_low
,
add_high
);
}
else
if
(
cr
==
must_carry
&&
(
is_Const
(
left_high
)
||
is_Const
(
right_high
)))
{
// We cannot assume that left_high and right_high form a normalized Add.
ir_node
*
constant
;
ir_node
*
other
;
if
(
is_Const
(
left_high
))
{
constant
=
left_high
;
other
=
right_high
;
}
else
{
constant
=
right_high
;
other
=
left_high
;
}
ir_graph
*
irg
=
get_irn_irg
(
right_high
);
ir_node
*
one
=
new_rd_Const
(
dbg
,
irg
,
get_mode_one
(
high_mode
));
ir_node
*
const_plus_one
=
new_rd_Add
(
dbg
,
block
,
constant
,
one
,
high_mode
);
ir_node
*
add_high
=
new_rd_Add
(
dbg
,
block
,
other
,
const_plus_one
,
high_mode
);
ir_node
*
add_low
=
new_rd_Add
(
dbg
,
block
,
left_low
,
right_low
,
low_mode
);
ir_set_dw_lowered
(
node
,
add_low
,
add_high
);
}
else
{
/* l_res = a_l + b_l */
...
...
@@ -148,27 +184,47 @@ static void ia32_lower_add64(ir_node *node, ir_mode *mode)
}
/**
* lower 64bit subtraction: a 32bit sub for the lower parts, a sub borrow
* for the higher parts.
* lower 64bit subtraction: a 32bit sub for the lower parts, a sub
* with borrow for the higher parts. If the borrow's value is known,
* fold it into the upper sub.
*/
static
void
ia32_lower_sub64
(
ir_node
*
node
,
ir_mode
*
mode
)
{
dbg_info
*
dbg
=
get_irn_dbg_info
(
node
);
ir_node
*
block
=
get_nodes_block
(
node
);
ir_node
*
left
=
get_Sub_left
(
node
);
ir_node
*
right
=
get_Sub_right
(
node
);
ir_node
*
left_low
=
get_lowered_low
(
left
);
ir_node
*
left_high
=
get_lowered_high
(
left
);
ir_node
*
right_low
=
get_lowered_low
(
right
);
ir_node
*
right_high
=
get_lowered_high
(
right
);
ir_mode
*
low_mode
=
get_irn_mode
(
left_low
);
dbg_info
*
dbg
=
get_irn_dbg_info
(
node
);
ir_node
*
block
=
get_nodes_block
(
node
);
ir_node
*
left
=
get_Sub_left
(
node
);
ir_node
*
right
=
get_Sub_right
(
node
);
ir_node
*
left_low
=
get_lowered_low
(
left
);
ir_node
*
left_high
=
get_lowered_high
(
left
);
ir_node
*
right_low
=
get_lowered_low
(
right
);
ir_node
*
right_high
=
get_lowered_high
(
right
);
ir_mode
*
low_mode
=
get_irn_mode
(
left_low
);
ir_mode
*
high_mode
=
get_irn_mode
(
left_high
);
carry_result
cr
=
lower_sub_borrow
(
left
,
right
,
low_mode
);
assert
(
get_irn_mode
(
left_low
)
==
get_irn_mode
(
right_low
));
assert
(
get_irn_mode
(
left_high
)
==
get_irn_mode
(
right_high
));
if
(
!
lower_sub_can_borrow
(
left
,
right
,
low_mode
)
)
{
if
(
cr
==
no_carry
)
{
ir_node
*
sub_low
=
new_rd_Sub
(
dbg
,
block
,
left_low
,
right_low
,
low_mode
);
ir_node
*
sub_high
=
new_rd_Sub
(
dbg
,
block
,
left_high
,
right_high
,
get_irn_mode
(
left_high
));
ir_node
*
sub_high
=
new_rd_Sub
(
dbg
,
block
,
left_high
,
right_high
,
high_mode
);
ir_set_dw_lowered
(
node
,
sub_low
,
sub_high
);
}
else
if
(
cr
==
must_carry
&&
(
is_Const
(
left_high
)
||
is_Const
(
right_high
)))
{
ir_node
*
sub_high
;
ir_graph
*
irg
=
get_irn_irg
(
right_high
);
ir_node
*
one
=
new_rd_Const
(
dbg
,
irg
,
get_mode_one
(
high_mode
));
if
(
is_Const
(
right_high
))
{
ir_node
*
new_const
=
new_rd_Add
(
dbg
,
block
,
right_high
,
one
,
high_mode
);
sub_high
=
new_rd_Sub
(
dbg
,
block
,
left_high
,
new_const
,
high_mode
);
}
else
if
(
is_Const
(
left_high
))
{
ir_node
*
new_const
=
new_rd_Sub
(
dbg
,
block
,
left_high
,
one
,
high_mode
);
sub_high
=
new_rd_Sub
(
dbg
,
block
,
new_const
,
right_high
,
high_mode
);
}
else
{
panic
(
"Logic error. This should never happen."
);
}
ir_node
*
sub_low
=
new_rd_Sub
(
dbg
,
block
,
left_low
,
right_low
,
low_mode
);
ir_set_dw_lowered
(
node
,
sub_low
,
sub_high
);
}
else
{
/* l_res = a_l - b_l */
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new 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