Commit d39d658d by Rask Ingemann Lambertsen Committed by Rask Ingemann Lambertsen

re PR target/30315 (optimize unsigned-add overflow test on x86 to use cpu flags from addl)

	PR target/30315
	* config/i386/i386.h (CANONICALIZE_COMPARISON): New.
	* config/i386/i386.md (plusminus)(addsub)(SWI): New.
	(*<addsub><mode>3_cc_overflow): New.
	(*add<mode>3_cconly_overflow): New.
	(*sub<mode>3_cconly_overflow): New.
	(*<addsub>si3_zext_cc_overflow): New.
	* config/i386/predicates.md (fcmov_comparison_operator): Accept
	CCCmode for LTU, GTU, LEU and GEU.
	(ix86_comparison_operator): Likewise.
	(ix86_carry_flag_operator): Carry flag is set if LTU or GTU in CCCmode.
	* gcc/config/i386/i386.c (put_condition_code): Support CCCmode.
	(ix86_cc_mode): Use CCCmode when testing for overflow of PLUS
	or MINUS expressions.

testsuite/
	PR target/30315
	* gcc.target/i386/pr30315.c: New.

From-SVN: r127481
parent 9a251aa1
2007-08-14 Rask Ingemann Lambertsen <rask@sygehus.dk>
PR target/30315
* config/i386/i386.h (CANONICALIZE_COMPARISON): New.
* config/i386/i386.md (plusminus)(addsub)(SWI): New.
(*<addsub><mode>3_cc_overflow): New.
(*add<mode>3_cconly_overflow): New.
(*sub<mode>3_cconly_overflow): New.
(*<addsub>si3_zext_cc_overflow): New.
* config/i386/predicates.md (fcmov_comparison_operator): Accept
CCCmode for LTU, GTU, LEU and GEU.
(ix86_comparison_operator): Likewise.
(ix86_carry_flag_operator): Carry flag is set if LTU or GTU in CCCmode.
* gcc/config/i386/i386.c (put_condition_code): Support CCCmode.
(ix86_cc_mode): Use CCCmode when testing for overflow of PLUS
or MINUS expressions.
2007-08-14 Andrew Pinski <pinskia@gmail.com>
PR c/30428
......
......@@ -8261,8 +8261,12 @@ put_condition_code (enum rtx_code code, enum machine_mode mode, int reverse,
case GTU:
/* ??? Use "nbe" instead of "a" for fcmov lossage on some assemblers.
Those same assemblers have the same but opposite lossage on cmov. */
gcc_assert (mode == CCmode);
suffix = fp ? "nbe" : "a";
if (mode == CCmode)
suffix = fp ? "nbe" : "a";
else if (mode == CCCmode)
suffix = "b";
else
gcc_unreachable ();
break;
case LT:
switch (mode)
......@@ -8282,7 +8286,7 @@ put_condition_code (enum rtx_code code, enum machine_mode mode, int reverse,
}
break;
case LTU:
gcc_assert (mode == CCmode);
gcc_assert (mode == CCmode || mode == CCCmode);
suffix = "b";
break;
case GE:
......@@ -8304,7 +8308,7 @@ put_condition_code (enum rtx_code code, enum machine_mode mode, int reverse,
break;
case GEU:
/* ??? As above. */
gcc_assert (mode == CCmode);
gcc_assert (mode == CCmode || mode == CCCmode);
suffix = fp ? "nb" : "ae";
break;
case LE:
......@@ -8312,8 +8316,13 @@ put_condition_code (enum rtx_code code, enum machine_mode mode, int reverse,
suffix = "le";
break;
case LEU:
gcc_assert (mode == CCmode);
suffix = "be";
/* ??? As above. */
if (mode == CCmode)
suffix = "be";
else if (mode == CCCmode)
suffix = fp ? "nb" : "ae";
else
gcc_unreachable ();
break;
case UNORDERED:
suffix = fp ? "u" : "p";
......@@ -11040,10 +11049,21 @@ ix86_cc_mode (enum rtx_code code, rtx op0, rtx op1)
return CCZmode;
/* Codes needing carry flag. */
case GEU: /* CF=0 */
case GTU: /* CF=0 & ZF=0 */
case LTU: /* CF=1 */
/* Detect overflow checks. They need just the carry flag. */
if (GET_CODE (op0) == PLUS
&& rtx_equal_p (op1, XEXP (op0, 0)))
return CCCmode;
else
return CCmode;
case GTU: /* CF=0 & ZF=0 */
case LEU: /* CF=1 | ZF=1 */
return CCmode;
/* Detect overflow checks. They need just the carry flag. */
if (GET_CODE (op0) == MINUS
&& rtx_equal_p (op1, XEXP (op0, 0)))
return CCCmode;
else
return CCmode;
/* Codes possibly doable only with sign flag when
comparing against zero. */
case GE: /* SF=OF or SF=0 */
......
......@@ -2065,6 +2065,16 @@ do { \
#define SELECT_CC_MODE(OP, X, Y) ix86_cc_mode ((OP), (X), (Y))
/* Canonicalize overflow checks to save on the insn patterns. We change
"a + b < b" into "a + b < a" and "a + b >= b" into "a + b >= a". */
#define CANONICALIZE_COMPARISON(code, op0, op1) \
{ \
if ((code == LTU || code == GEU) \
&& GET_CODE (op0) == PLUS \
&& rtx_equal_p (op1, XEXP (op0, 1))) \
op1 = XEXP (op0, 0); \
}
/* Return nonzero if MODE implies a floating point inequality can be
reversed. */
......
......@@ -488,6 +488,33 @@
[(set_attr "length" "128")
(set_attr "type" "multi")])
(define_code_macro plusminus [plus minus])
;; Base name for define_insn and insn mnemonic.
(define_code_attr addsub [(plus "add") (minus "sub")])
;; Mark commutative operators as such in constraints.
(define_code_attr comm [(plus "%") (minus "")])
;; All single word integer modes.
(define_mode_macro SWI [QI HI SI (DI "TARGET_64BIT")])
;; Instruction suffix for integer modes.
(define_mode_attr imodesuffix [(QI "b") (HI "w") (SI "l") (DI "q")])
;; Register class for integer modes.
(define_mode_attr r [(QI "q") (HI "r") (SI "r") (DI "r")])
;; Immediate operand constraint for integer modes.
(define_mode_attr i [(QI "i") (HI "i") (SI "i") (DI "e")])
;; General operand predicate for integer modes.
(define_mode_attr general_operand
[(QI "general_operand")
(HI "general_operand")
(SI "general_operand")
(DI "x86_64_general_operand")])
;; All x87 floating point modes
(define_mode_macro X87MODEF [SF DF XF])
......@@ -4855,6 +4882,56 @@
[(set_attr "type" "alu")
(set_attr "mode" "DI")])
(define_insn "*<addsub><mode>3_cc_overflow"
[(set (reg:CCC FLAGS_REG)
(compare:CCC
(plusminus:SWI
(match_operand:SWI 1 "nonimmediate_operand" "<comm>0,0")
(match_operand:SWI 2 "<general_operand>" "<r><i>,<r>m"))
(match_dup 1)))
(set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m,<r>")
(plusminus:SWI (match_dup 1) (match_dup 2)))]
"ix86_binary_operator_ok (<CODE>, <MODE>mode, operands)"
"<addsub>{<imodesuffix>}\t{%2, %0|%0, %2}"
[(set_attr "type" "alu")
(set_attr "mode" "<MODE>")])
(define_insn "*add<mode>3_cconly_overflow"
[(set (reg:CCC FLAGS_REG)
(compare:CCC
(plus:SWI (match_operand:SWI 1 "nonimmediate_operand" "%0")
(match_operand:SWI 2 "<general_operand>" "<r><i>m"))
(match_dup 1)))
(clobber (match_scratch:SWI 0 "=<r>"))]
"ix86_binary_operator_ok (PLUS, <MODE>mode, operands)"
"add{<imodesuffix>}\t{%2, %0|%0, %2}"
[(set_attr "type" "alu")
(set_attr "mode" "<MODE>")])
(define_insn "*sub<mode>3_cconly_overflow"
[(set (reg:CCC FLAGS_REG)
(compare:CCC
(minus:SWI (match_operand:SWI 0 "nonimmediate_operand" "<r>m,<r>")
(match_operand:SWI 1 "<general_operand>" "<r><i>,<r>m"))
(match_dup 0)))]
""
"cmp{<imodesuffix>}\t{%1, %0|%0, %1}"
[(set_attr "type" "icmp")
(set_attr "mode" "<MODE>")])
(define_insn "*<addsub>si3_zext_cc_overflow"
[(set (reg:CCC FLAGS_REG)
(compare:CCC
(plusminus:SI (match_operand:SI 1 "nonimmediate_operand" "<comm>0")
(match_operand:SI 2 "general_operand" "g"))
(match_dup 1)))
(set (match_operand:DI 0 "register_operand" "=r")
(zero_extend:DI (plusminus:SI (match_dup 1) (match_dup 2))))]
"TARGET_64BIT && ix86_binary_operator_ok (<CODE>, SImode, operands)"
"<addsub>{l}\t{%2, %k0|%k0, %2}"
[(set_attr "type" "alu")
(set_attr "mode" "SI")])
(define_insn "addqi3_carry"
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
(plus:QI (plus:QI (match_operand:QI 3 "ix86_carry_flag_operator" "")
......
......@@ -879,7 +879,8 @@
switch (code)
{
case LTU: case GTU: case LEU: case GEU:
if (inmode == CCmode || inmode == CCFPmode || inmode == CCFPUmode)
if (inmode == CCmode || inmode == CCFPmode || inmode == CCFPUmode
|| inmode == CCCmode)
return 1;
return 0;
case ORDERED: case UNORDERED:
......@@ -924,7 +925,11 @@
|| inmode == CCGOCmode || inmode == CCNOmode)
return 1;
return 0;
case LTU: case GTU: case LEU: case ORDERED: case UNORDERED: case GEU:
case LTU: case GTU: case LEU: case GEU:
if (inmode == CCmode || inmode == CCCmode)
return 1;
return 0;
case ORDERED: case UNORDERED:
if (inmode == CCmode)
return 1;
return 0;
......@@ -939,7 +944,7 @@
;; Return 1 if OP is a valid comparison operator testing carry flag to be set.
(define_predicate "ix86_carry_flag_operator"
(match_code "ltu,lt,unlt,gt,ungt,le,unle,ge,unge,ltgt,uneq")
(match_code "ltu,lt,unlt,gtu,gt,ungt,le,unle,ge,unge,ltgt,uneq")
{
enum machine_mode inmode = GET_MODE (XEXP (op, 0));
enum rtx_code code = GET_CODE (op);
......@@ -957,6 +962,8 @@
return 0;
code = ix86_fp_compare_code_to_integer (code);
}
else if (inmode == CCCmode)
return code == LTU || code == GTU;
else if (inmode != CCmode)
return 0;
......
2007-08-14 Rask Ingemann Lambertsen <rask@sygehus.dk>
PR target/30315
* gcc.target/i386/pr30315.c: New.
2007-08-14 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
PR fortran/32594
/* { dg-do compile } */
/* { dg-options "-O2" } */
/* { dg-final { scan-assembler-times "cmp" 4 } } */
extern void abort (void);
int c;
#define PLUSCC1(T, t, C) \
T pluscc##t##C (T a, T b) \
{ \
T sum = a + b; \
if (sum < C) \
abort (); \
return sum; \
}
#define PLUSCC(T, t) PLUSCC1(T, t, a) PLUSCC1(T, t, b)
#define INCCC1(T, t, C) \
T inccc##t##C (T a, T b) \
{ \
T sum = a + b; \
if (sum < C) \
c ++; \
return sum; \
}
#define INCCC(T, t) INCCC1(T, t, a) INCCC1(T, t, b)
#define PLUSCCONLY1(T, t, C) \
void pluscconly##t##C (T a, T b) \
{ \
T sum = a + b; \
if (sum < C) \
abort (); \
}
#define PLUSCCONLY(T, t) PLUSCCONLY1(T, t, a) PLUSCCONLY1(T, t, b)
#define MINUSCC(T, t) \
T minuscc##t (T a, T b) \
{ \
T difference = a - b; \
if (difference > a) \
abort (); \
return difference; \
}
#define DECCC(T, t) \
T deccc##t (T a, T b) \
{ \
T difference = a - b; \
if (difference > a) \
c --; \
return difference; \
}
#define MINUSCCONLY(T, t) \
void minuscconly##t (T a, T b) \
{ \
T difference = a - b; \
if (difference > a) \
abort (); \
}
#define TEST(T, t) \
PLUSCC(T, t) \
PLUSCCONLY(T, t) \
INCCC(T, t) \
MINUSCC(T, t) \
MINUSCCONLY(T, t) \
DECCC(T, t)
TEST (unsigned long, l)
TEST (unsigned int, i)
TEST (unsigned short, s)
TEST (unsigned char, c)
#define PLUSCCZEXT(C) \
unsigned long pluscczext##C (unsigned int a, unsigned int b) \
{ \
unsigned int sum = a + b; \
if (sum < C) \
abort (); \
return sum; \
}
PLUSCCZEXT(a)
PLUSCCZEXT(b)
#define MINUSCCZEXT \
unsigned long minuscczext (unsigned int a, unsigned int b) \
{ \
unsigned int difference = a - b; \
if (difference > a) \
abort (); \
return difference; \
}
MINUSCCZEXT
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment