------- Comment #4 from rask at sygehus dot dk 2007-06-06 10:33 -------
I see no reason to mark this enhancement request as invalid.
As to generating reasonable x86 code for overflow checks written in C, it
isn't completely hopeless. I did an experiment with my 16-bit x86 port. First,
I wrote the overflow check differently (and of course changed the data size to
16-bits):
#include <limits.h>
void abort (void);
unsigned short int foo (unsigned short int a, unsigned short int b)
{
unsigned short int sum;
sum = a + b;
if ((unsigned long int) a + (unsigned long int) b > USHRT_MAX)
abort ();
return sum;
}
Second, I added new instructions, of which combine was asking for the first
one:
(define_insn_and_split "*addsi3_cconly_highpart_ccz_nc"
[(set (reg:CCZ_NC CC_REG)
(compare:CCZ_NC
(subreg:HI (plus:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "general_operand" "g")) 2)
(const_int 0)))
(clobber (match_scratch:HI 0 "=r"))]
"ia16_arith_operands_p (PLUS, operands)"
"#"
""
[(parallel
[(set (match_dup 0) (plus:HI (match_dup 3) (match_dup 4)))
(set (reg:CCZ_NC CC_REG)
(compare:CCZ_NC (subreg:HI (plus:SI (zero_extend:SI (match_dup 3))
(zero_extend:SI (match_dup 4))) 2)
(const_int 0)))]
)]
{
operands[3] = simplify_gen_subreg (HImode, operands[1], SImode, 0);
operands[4] = simplify_gen_subreg (HImode, operands[2], SImode, 0);
})
(define_insn "*addhi3_cc_carry_ccz_nc"
[(set (match_operand:HI 0 "nonimmediate_operand" "=qm,r,m")
(plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,0")
(match_operand:HI 2 "general_operand" "Uo,g,ri")))
(set (reg:CCZ_NC CC_REG)
(compare:CCZ_NC
(subreg:HI (plus:SI (zero_extend:SI (match_dup 1))
(zero_extend:SI (match_dup 2))) 2)
(const_int 0)))]
"ia16_arith_operands_p (PLUS, operands)"
"@
addb\t%H2,\t%H0
addw\t%2,\t%0
addw\t%2,\t%0"
)
(define_insn "*addhi3_cconly_carry_ccz_nc"
[(set (match_scratch:HI 0 "=qm,r,m")
(plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,0")
(match_operand:HI 2 "general_operand" "Uo,g,ri")))
(set (reg:CCZ_NC CC_REG)
(compare:CCZ_NC
(subreg:HI (plus:SI (zero_extend:SI (match_dup 1))
(zero_extend:SI (match_dup 2))) 2)
(const_int 0)))]
"ia16_arith_operands_p (PLUS, operands)"
"@
addb\t%H2,\t%H0
addw\t%2,\t%0
addw\t%2,\t%0"
)
(define_insn "*beq_ccz_nc"
[(set (pc)
(if_then_else (eq (reg:CCZ_NC CC_REG)
(const_int 0))
(label_ref (match_operand 0))
(pc)))]
""
"jnc\t%l0"
)
Third, I created CCZ_NCmode and modified my SELECT_CC_MODE callback to use
it for the comparison in "*addsi3_cconly_highpart_ccz_nc". Result:
foo:
pushw %cx ;# 69 *pushhi1_nonimm
pushw %si ;# 70 *pushhi1_nonimm
pushw %di ;# 71 *pushhi1_nonimm
pushw %bp ;# 72 *pushhi1_nonimm
movw %sp, %bp ;# 67 *movhi/1
movw 10(%bp),%di ;# 2 *movhi/1
movw %sp, %si ;# 68 *movhi/1
movw 12(%si),%bp ;# 3 *movhi/1
movw %bp, %ax ;# 7 *movhi/1
addw %di, %ax ;# 63 *addhi3_cc_carry_ccz_nc/2
jnc .L7 ;# 15 *beq_ccz_nc
call abort ;# 25 *call
.L7:
popw %bp ;# 75 *pophi1
popw %di ;# 76 *pophi1
popw %si ;# 77 *pophi1
popw %cx ;# 78 *pophi1
ret ;# 79 *return
I see no reason the i386 back end can't be improved in a similiar fashion.
The original example is a lot more difficult because it uses two
comparisons. The middle end would have to recognize that the two comparisons
test the same thing.
--
rask at sygehus dot dk changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |rask at sygehus dot dk
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30315