compare-elim.c (conforming_compare): Accept UNSPECs.

* compare-elim.c (conforming_compare): Accept UNSPECs.
	(find_comparison_dom_walker::before_dom_children): Deal with
	instructions both using and killing the flags register.
	(equivalent_reg_at_start): New function extracted from...
	(try_eliminate_compare): ...here.  Use it and add support for
	registers and UNSPECs as second operand of the compare.
	* config/visium/visium-modes.def (CCV): New.
	* config/visium/predicates.md (visium_v_comparison_operator): New.
	(visium_branch_operator): Deal with CCV mode.
	* config/visium/visium.c (visium_select_cc_mode): Likewise.
	(output_cbranch): Likewise.
	* config/visium/visium.md (UNSPEC_{ADD,SUB,NEG}V): New constants.
	(uaddv<mode>4): New expander.
	(addv<mode>4): Likewise.
	(add<mode>3_insn_set_carry): New instruction.
	(add<mode>3_insn_set_overflow): Likewise.
	(addsi3_insn_set_overflow): Likewise.
	(usubv<mode>4): New expander.
	(subv<mode>4): Likewise.
	(sub<mode>3_insn_set_carry): New instruction.
	(sub<mode>3_insn_set_overflow): Likewise.
	(subsi3_insn_set_overflow): Likewise.
	(unegv<mode>3): New expander.
	(negv<mode>3): Likewise.
	(neg<mode>2_insn_set_overflow): New instruction.
	(addv_tst<mode>): Likewise.
	(subv_tst<mode>): Likewise.
	(negv_tst<mode>): Likewise.
	(cbranch<mode>4_addv_insn): New splitter and instruction.
	(cbranch<mode>4_subv_insn): Likewise.
	(cbranch<mode>4_negv_insn): Likewise.

From-SVN: r241379
This commit is contained in:
Eric Botcazou 2016-10-20 14:38:43 +00:00 committed by Eric Botcazou
parent 40b8428e2e
commit 2c35bbe14a
10 changed files with 543 additions and 61 deletions

View File

@ -1,3 +1,37 @@
2016-10-20 Eric Botcazou <ebotcazou@adacore.com>
* compare-elim.c (conforming_compare): Accept UNSPECs.
(find_comparison_dom_walker::before_dom_children): Deal with
instructions both using and killing the flags register.
(equivalent_reg_at_start): New function extracted from...
(try_eliminate_compare): ...here. Use it and add support for
registers and UNSPECs as second operand of the compare.
* config/visium/visium-modes.def (CCV): New.
* config/visium/predicates.md (visium_v_comparison_operator): New.
(visium_branch_operator): Deal with CCV mode.
* config/visium/visium.c (visium_select_cc_mode): Likewise.
(output_cbranch): Likewise.
* config/visium/visium.md (UNSPEC_{ADD,SUB,NEG}V): New constants.
(uaddv<mode>4): New expander.
(addv<mode>4): Likewise.
(add<mode>3_insn_set_carry): New instruction.
(add<mode>3_insn_set_overflow): Likewise.
(addsi3_insn_set_overflow): Likewise.
(usubv<mode>4): New expander.
(subv<mode>4): Likewise.
(sub<mode>3_insn_set_carry): New instruction.
(sub<mode>3_insn_set_overflow): Likewise.
(subsi3_insn_set_overflow): Likewise.
(unegv<mode>3): New expander.
(negv<mode>3): Likewise.
(neg<mode>2_insn_set_overflow): New instruction.
(addv_tst<mode>): Likewise.
(subv_tst<mode>): Likewise.
(negv_tst<mode>): Likewise.
(cbranch<mode>4_addv_insn): New splitter and instruction.
(cbranch<mode>4_subv_insn): Likewise.
(cbranch<mode>4_negv_insn): Likewise.
2016-10-20 Richard Biener <rguenther@suse.de>
* tree-ssa-alias.c (ptrs_compare_unequal): Remove code duplication.

View File

@ -143,10 +143,20 @@ conforming_compare (rtx_insn *insn)
if (!REG_P (dest) || REGNO (dest) != targetm.flags_regnum)
return NULL;
if (REG_P (XEXP (src, 0))
&& (REG_P (XEXP (src, 1)) || CONSTANT_P (XEXP (src, 1))))
if (!REG_P (XEXP (src, 0)))
return NULL;
if (CONSTANT_P (XEXP (src, 1)) || REG_P (XEXP (src, 1)))
return src;
if (GET_CODE (XEXP (src, 1)) == UNSPEC)
{
for (int i = 0; i < XVECLEN (XEXP (src, 1), 0); i++)
if (!REG_P (XVECEXP (XEXP (src, 1), 0, i)))
return NULL;
return src;
}
return NULL;
}
@ -370,22 +380,25 @@ find_comparison_dom_walker::before_dom_children (basic_block bb)
last_cmp_valid = true;
}
/* Notice if this instruction kills the flags register. */
else if (bitmap_bit_p (killed, targetm.flags_regnum))
else
{
/* See if this insn could be the "clobber" that eliminates
a future comparison. */
last_clobber = (arithmetic_flags_clobber_p (insn) ? insn : NULL);
/* Notice if this instruction uses the flags register. */
if (last_cmp)
find_flags_uses_in_insn (last_cmp, insn);
/* In either case, the previous compare is no longer valid. */
last_cmp = NULL;
last_cmp_valid = false;
/* Notice if this instruction kills the flags register. */
if (bitmap_bit_p (killed, targetm.flags_regnum))
{
/* See if this insn could be the "clobber" that eliminates
a future comparison. */
last_clobber = (arithmetic_flags_clobber_p (insn) ? insn : NULL);
/* In either case, the previous compare is no longer valid. */
last_cmp = NULL;
last_cmp_valid = false;
}
}
/* Notice if this instruction uses the flags register. */
else if (last_cmp)
find_flags_uses_in_insn (last_cmp, insn);
/* Notice if any of the inputs to the comparison have changed. */
if (last_cmp_valid
&& (bitmap_bit_p (killed, REGNO (last_cmp->in_a))
@ -507,39 +520,16 @@ maybe_select_cc_mode (struct comparison *cmp, rtx a ATTRIBUTE_UNUSED,
return flags;
}
/* Attempt to replace a comparison with a prior arithmetic insn that can
compute the same flags value as the comparison itself. Return true if
successful, having made all rtl modifications necessary. */
/* Return a register RTX holding the same value at START as REG at END, or
NULL_RTX if there is none. */
static bool
try_eliminate_compare (struct comparison *cmp)
static rtx
equivalent_reg_at_start (rtx reg, rtx_insn *end, rtx_insn *start)
{
rtx_insn *insn, *bb_head;
rtx x, flags, in_a, cmp_src;
rtx_insn *bb_head = BB_HEAD (BLOCK_FOR_INSN (end));
/* We must have found an interesting "clobber" preceding the compare. */
if (cmp->prev_clobber == NULL)
return false;
/* ??? For the moment we don't handle comparisons for which IN_B
is a register. We accepted these during initial comparison
recognition in order to eliminate duplicate compares.
An improvement here would be to handle x = a - b; if (a cmp b). */
if (!CONSTANT_P (cmp->in_b))
return false;
/* Verify that IN_A is not clobbered in between CMP and PREV_CLOBBER.
Given that this target requires this pass, we can assume that most
insns do clobber the flags, and so the distance between the compare
and the clobber is likely to be small. */
/* ??? This is one point at which one could argue that DF_REF_CHAIN would
be useful, but it is thought to be too heavy-weight a solution here. */
in_a = cmp->in_a;
insn = cmp->insn;
bb_head = BB_HEAD (BLOCK_FOR_INSN (insn));
for (insn = PREV_INSN (insn);
insn != cmp->prev_clobber;
for (rtx_insn *insn = PREV_INSN (end);
insn != start;
insn = PREV_INSN (insn))
{
const int abnormal_flags
@ -552,13 +542,13 @@ try_eliminate_compare (struct comparison *cmp)
/* Note that the BB_HEAD is always either a note or a label, but in
any case it means that IN_A is defined outside the block. */
if (insn == bb_head)
return false;
return NULL_RTX;
if (NOTE_P (insn) || DEBUG_INSN_P (insn))
continue;
/* Find a possible def of IN_A in INSN. */
FOR_EACH_INSN_DEF (def, insn)
if (DF_REF_REGNO (def) == REGNO (in_a))
if (DF_REF_REGNO (def) == REGNO (reg))
break;
/* No definitions of IN_A; continue searching. */
@ -567,35 +557,87 @@ try_eliminate_compare (struct comparison *cmp)
/* Bail if this is not a totally normal set of IN_A. */
if (DF_REF_IS_ARTIFICIAL (def))
return false;
return NULL_RTX;
if (DF_REF_FLAGS (def) & abnormal_flags)
return false;
return NULL_RTX;
/* We've found an insn between the compare and the clobber that sets
IN_A. Given that pass_cprop_hardreg has not yet run, we still find
situations in which we can usefully look through a copy insn. */
x = single_set (insn);
if (x == NULL)
return false;
in_a = SET_SRC (x);
if (!REG_P (in_a))
rtx x = single_set (insn);
if (x == NULL_RTX)
return NULL_RTX;
reg = SET_SRC (x);
if (!REG_P (reg))
return NULL_RTX;
}
return reg;
}
/* Attempt to replace a comparison with a prior arithmetic insn that can
compute the same flags value as the comparison itself. Return true if
successful, having made all rtl modifications necessary. */
static bool
try_eliminate_compare (struct comparison *cmp)
{
rtx x, flags, in_a, in_b, cmp_src;
/* We must have found an interesting "clobber" preceding the compare. */
if (cmp->prev_clobber == NULL)
return false;
/* Verify that IN_A is not clobbered in between CMP and PREV_CLOBBER.
Given that this target requires this pass, we can assume that most
insns do clobber the flags, and so the distance between the compare
and the clobber is likely to be small. */
/* ??? This is one point at which one could argue that DF_REF_CHAIN would
be useful, but it is thought to be too heavy-weight a solution here. */
in_a = equivalent_reg_at_start (cmp->in_a, cmp->insn, cmp->prev_clobber);
if (!in_a)
return false;
/* Likewise for IN_B if need be. */
if (CONSTANT_P (cmp->in_b))
in_b = cmp->in_b;
else if (REG_P (cmp->in_b))
{
in_b = equivalent_reg_at_start (cmp->in_b, cmp->insn, cmp->prev_clobber);
if (!in_b)
return false;
}
else if (GET_CODE (cmp->in_b) == UNSPEC)
{
const int len = XVECLEN (cmp->in_b, 0);
rtvec v = rtvec_alloc (len);
for (int i = 0; i < len; i++)
{
rtx r = equivalent_reg_at_start (XVECEXP (cmp->in_b, 0, i),
cmp->insn, cmp->prev_clobber);
if (!r)
return false;
RTVEC_ELT (v, i) = r;
}
in_b = gen_rtx_UNSPEC (GET_MODE (cmp->in_b), v, XINT (cmp->in_b, 1));
}
else
gcc_unreachable ();
/* We've reached PREV_CLOBBER without finding a modification of IN_A.
Validate that PREV_CLOBBER itself does in fact refer to IN_A. Do
recall that we've already validated the shape of PREV_CLOBBER. */
rtx insn = cmp->prev_clobber;
x = XVECEXP (PATTERN (insn), 0, 0);
if (rtx_equal_p (SET_DEST (x), in_a))
cmp_src = SET_SRC (x);
/* Also check operations with implicit extensions, e.g.:
[(set (reg:DI)
(zero_extend:DI (plus:SI (reg:SI)(reg:SI))))
(zero_extend:DI (plus:SI (reg:SI) (reg:SI))))
(set (reg:CCZ flags)
(compare:CCZ
(plus:SI (reg:SI)(reg:SI))
(const_int 0)))] */
(compare:CCZ (plus:SI (reg:SI) (reg:SI))
(const_int 0)))] */
else if (REG_P (SET_DEST (x))
&& REG_P (in_a)
&& REGNO (SET_DEST (x)) == REGNO (in_a)
@ -603,17 +645,29 @@ try_eliminate_compare (struct comparison *cmp)
|| GET_CODE (SET_SRC (x)) == SIGN_EXTEND)
&& GET_MODE (XEXP (SET_SRC (x), 0)) == GET_MODE (in_a))
cmp_src = XEXP (SET_SRC (x), 0);
/* Also check fully redundant comparisons, e.g.:
[(set (reg:SI)
(minus:SI (reg:SI) (reg:SI))))
(set (reg:CC flags)
(compare:CC (reg:SI) (reg:SI)))] */
else if (REG_P (in_b)
&& GET_CODE (SET_SRC (x)) == MINUS
&& rtx_equal_p (XEXP (SET_SRC (x), 0), in_a)
&& rtx_equal_p (XEXP (SET_SRC (x), 1), in_b))
cmp_src = in_a;
else
return false;
/* Determine if we ought to use a different CC_MODE here. */
flags = maybe_select_cc_mode (cmp, cmp_src, cmp->in_b);
flags = maybe_select_cc_mode (cmp, cmp_src, in_b);
if (flags == NULL)
flags = gen_rtx_REG (cmp->orig_mode, targetm.flags_regnum);
/* Generate a new comparison for installation in the setter. */
x = copy_rtx (cmp_src);
x = gen_rtx_COMPARE (GET_MODE (flags), x, cmp->in_b);
x = gen_rtx_COMPARE (GET_MODE (flags), x, in_b);
x = gen_rtx_SET (flags, x);
/* Succeed if the new instruction is valid. Note that we may have started

View File

@ -131,13 +131,17 @@
(match_code "eq,ne"))
;; Return true if OP is a valid comparison operator for CCNZmode.
(define_special_predicate "visium_nz_comparison_operator"
(define_predicate "visium_nz_comparison_operator"
(match_code "eq,ne,lt,ge"))
;; Return true if OP is a valid comparison operator for CCCmode.
(define_special_predicate "visium_c_comparison_operator"
(define_predicate "visium_c_comparison_operator"
(match_code "eq,ne,ltu,geu"))
;; Return true if OP is a valid comparison operator for CCVmode.
(define_predicate "visium_v_comparison_operator"
(match_code "eq,ne"))
;; Return true if OP is a valid FP comparison operator.
(define_predicate "visium_fp_comparison_operator"
(match_code "eq,ne,ordered,unordered,unlt,unle,ungt,unge,lt,le,gt,ge"))
@ -155,6 +159,8 @@
return visium_nz_comparison_operator (op, mode);
case CCCmode:
return visium_c_comparison_operator (op, mode);
case CCVmode:
return visium_v_comparison_operator (op, mode);
case CCFPmode:
case CCFPEmode:
return visium_fp_comparison_operator (op, mode);

View File

@ -29,6 +29,10 @@ along with GCC; see the file COPYING3. If not see
instruction. Only the =,!= and unsigned <,>= operators can be used in
conjunction with it.
We also have a CCVmode which is used by the arithmetic instructions when
they explicitly set the V flag (signed overflow). Only the =,!= operators
can be used in conjunction with it.
We also have two modes to indicate that the condition code is set by the
the floating-point unit. One for comparisons which generate an exception
if the result is unordered (CCFPEmode) and one for comparisons which never
@ -36,5 +40,6 @@ along with GCC; see the file COPYING3. If not see
CC_MODE (CCNZ);
CC_MODE (CCC);
CC_MODE (CCV);
CC_MODE (CCFP);
CC_MODE (CCFPE);

View File

@ -2833,6 +2833,14 @@ visium_select_cc_mode (enum rtx_code code, rtx op0, rtx op1)
&& rtx_equal_p (XEXP (op0, 0), op1))
return CCCmode;
/* This is for the {add,sub,neg}<mode>3_insn_set_overflow pattern. */
if ((code == EQ || code == NE)
&& GET_CODE (op1) == UNSPEC
&& (XINT (op1, 1) == UNSPEC_ADDV
|| XINT (op1, 1) == UNSPEC_SUBV
|| XINT (op1, 1) == UNSPEC_NEGV))
return CCVmode;
if (op1 != const0_rtx)
return CCmode;
@ -3101,6 +3109,8 @@ output_cbranch (rtx label, enum rtx_code code, enum machine_mode cc_mode,
case NE:
if (cc_mode == CCCmode)
cond = "cs";
else if (cc_mode == CCVmode)
cond = "os";
else
cond = "ne";
break;
@ -3108,6 +3118,8 @@ output_cbranch (rtx label, enum rtx_code code, enum machine_mode cc_mode,
case EQ:
if (cc_mode == CCCmode)
cond = "cc";
else if (cc_mode == CCVmode)
cond = "oc";
else
cond = "eq";
break;

View File

@ -81,6 +81,9 @@
UNSPEC_ITOF
UNSPEC_FTOI
UNSPEC_NOP
UNSPEC_ADDV
UNSPEC_SUBV
UNSPEC_NEGV
])
;; UNSPEC_VOLATILE usage.
@ -745,6 +748,27 @@
(match_operand:QHI 2 "register_operand" "")))]
"")
(define_expand "uaddv<mode>4"
[(set (match_operand:I 0 "register_operand" "")
(plus:I (match_operand:I 1 "register_operand" "")
(match_operand:I 2 "register_operand" "")))
(set (pc)
(if_then_else (ltu (match_dup 0) (match_dup 1))
(label_ref (match_operand 3 ""))
(pc)))]
"")
(define_expand "addv<mode>4"
[(set (match_operand:I 0 "register_operand" "")
(plus:I (match_operand:I 1 "register_operand" "")
(match_operand:I 2 "register_operand" "")))
(set (pc)
(if_then_else (ne (match_dup 0)
(unspec:I [(match_dup 1) (match_dup 2)] UNSPEC_ADDV))
(label_ref (match_operand 3 ""))
(pc)))]
"")
(define_insn_and_split "*add<mode>3_insn"
[(set (match_operand:QHI 0 "register_operand" "=r")
(plus:QHI (match_operand:QHI 1 "register_operand" "%r")
@ -767,6 +791,28 @@
"add<s> %0,%1,%2"
[(set_attr "type" "arith")])
(define_insn "*add<mode>3_insn_set_carry"
[(set (match_operand:QHI 0 "register_operand" "=r")
(plus:QHI (match_operand:QHI 1 "register_operand" "%r")
(match_operand:QHI 2 "register_operand" "r")))
(set (reg:CCC R_FLAGS)
(compare:CCC (plus:QHI (match_dup 1) (match_dup 2))
(match_dup 1)))]
"reload_completed"
"add<s> %0,%1,%2"
[(set_attr "type" "arith")])
(define_insn "*add<mode>3_insn_set_overflow"
[(set (match_operand:QHI 0 "register_operand" "=r")
(plus:QHI (match_operand:QHI 1 "register_operand" "%r")
(match_operand:QHI 2 "register_operand" "r")))
(set (reg:CCV R_FLAGS)
(compare:CCV (plus:QHI (match_dup 1) (match_dup 2))
(unspec:QHI [(match_dup 1) (match_dup 2)] UNSPEC_ADDV)))]
"reload_completed"
"add<s> %0,%1,%2"
[(set_attr "type" "arith")])
(define_expand "addsi3"
[(set (match_operand:SI 0 "register_operand" "")
(plus:SI (match_operand:SI 1 "register_operand" "")
@ -822,6 +868,19 @@
addi %0,%2"
[(set_attr "type" "arith")])
(define_insn "*addsi3_insn_set_overflow"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(plus:SI (match_operand:SI 1 "register_operand" "%r,0")
(match_operand:SI 2 "real_add_operand" " r,J")))
(set (reg:CCV R_FLAGS)
(compare:CCV (plus:SI (match_dup 1) (match_dup 2))
(unspec:SI [(match_dup 1) (match_dup 2)] UNSPEC_ADDV)))]
"reload_completed"
"@
add.l %0,%1,%2
addi %0,%2"
[(set_attr "type" "arith")])
(define_expand "adddi3"
[(set (match_operand:DI 0 "register_operand" "")
(plus:DI (match_operand:DI 1 "register_operand" "")
@ -897,6 +956,34 @@
(match_operand:QHI 2 "register_operand" "")))]
"")
(define_expand "usubv<mode>4"
[(set (match_operand:I 0 "register_operand" "")
(minus:I (match_operand:I 1 "reg_or_0_operand" "")
(match_operand:I 2 "register_operand" "")))
(set (pc)
(if_then_else (ltu (match_dup 1) (match_dup 2))
(label_ref (match_operand 3 ""))
(pc)))]
""
{
if (operands[1] == const0_rtx)
{
emit_insn (gen_unegv<mode>3 (operands[0], operands[2], operands[3]));
DONE;
}
})
(define_expand "subv<mode>4"
[(set (match_operand:I 0 "register_operand" "")
(minus:I (match_operand:I 1 "register_operand" "")
(match_operand:I 2 "register_operand" "")))
(set (pc)
(if_then_else (ne (match_dup 0)
(unspec:I [(match_dup 1) (match_dup 2)] UNSPEC_SUBV))
(label_ref (match_operand 3 ""))
(pc)))]
"")
(define_insn_and_split "*sub<mode>3_insn"
[(set (match_operand:QHI 0 "register_operand" "=r")
(minus:QHI (match_operand:QHI 1 "reg_or_0_operand" "rO")
@ -919,6 +1006,27 @@
"sub<s> %0,%r1,%2"
[(set_attr "type" "arith")])
(define_insn "*sub<mode>3_insn_set_carry"
[(set (match_operand:QHI 0 "register_operand" "=r")
(minus:QHI (match_operand:QHI 1 "reg_or_0_operand" "rO")
(match_operand:QHI 2 "register_operand" "r")))
(set (reg:CC R_FLAGS)
(compare:CC (match_dup 1) (match_dup 2)))]
"reload_completed"
"sub<s> %0,%r1,%2"
[(set_attr "type" "arith")])
(define_insn "*sub<mode>3_insn_set_overflow"
[(set (match_operand:QHI 0 "register_operand" "=r")
(minus:QHI (match_operand:QHI 1 "reg_or_0_operand" "rO")
(match_operand:QHI 2 "register_operand" "r")))
(set (reg:CCV R_FLAGS)
(compare:CCV (minus:QHI (match_dup 1) (match_dup 2))
(unspec:QHI [(match_dup 1) (match_dup 2)] UNSPEC_SUBV)))]
"reload_completed"
"sub<s> %0,%r1,%2"
[(set_attr "type" "arith")])
(define_expand "subsi3"
[(set (match_operand:SI 0 "register_operand" "")
(minus:SI (match_operand:SI 1 "reg_or_0_operand" "")
@ -973,6 +1081,19 @@
subi %0,%2"
[(set_attr "type" "arith")])
(define_insn "*subsi3_insn_set_overflow"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(minus:SI (match_operand:SI 1 "register_operand" " r,0")
(match_operand:SI 2 "real_add_operand" " r,J")))
(set (reg:CCV R_FLAGS)
(compare:CCV (minus:SI (match_dup 1) (match_dup 2))
(unspec:SI [(match_dup 1) (match_dup 2)] UNSPEC_SUBV)))]
"reload_completed"
"@
sub.l %0,%1,%2
subi %0,%2"
[(set_attr "type" "arith")])
(define_expand "subdi3"
[(set (match_operand:DI 0 "register_operand" "")
(minus:DI (match_operand:DI 1 "register_operand" "")
@ -1047,6 +1168,25 @@
(neg:I (match_operand:I 1 "register_operand" "")))]
"")
(define_expand "unegv<mode>3"
[(set (match_operand:I 0 "register_operand" "")
(neg:I (match_operand:I 1 "register_operand" "")))
(set (pc)
(if_then_else (ne (match_dup 0) (const_int 0))
(label_ref (match_operand 2 ""))
(pc)))]
"")
(define_expand "negv<mode>3"
[(set (match_operand:I 0 "register_operand" "")
(neg:I (match_operand:I 1 "register_operand" "")))
(set (pc)
(if_then_else (ne (match_dup 0)
(unspec:I [(match_dup 1)] UNSPEC_NEGV))
(label_ref (match_operand 2 ""))
(pc)))]
"")
(define_insn_and_split "*neg<mode>2_insn"
[(set (match_operand:I 0 "register_operand" "=r")
(neg:I (match_operand:I 1 "register_operand" "r")))]
@ -1075,6 +1215,16 @@
"sub.l %0,r0,%1"
[(set_attr "type" "arith")])
(define_insn "*neg<mode>2_insn_set_overflow"
[(set (match_operand:I 0 "register_operand" "=r")
(neg:I (match_operand:I 1 "register_operand" "r")))
(set (reg:CCV R_FLAGS)
(compare:CCV (neg:I (match_dup 1))
(unspec:I [(match_dup 1)] UNSPEC_NEGV)))]
"reload_completed"
"sub<s> %0,r0,%1"
[(set_attr "type" "arith")])
(define_expand "negdi2"
[(set (match_operand:DI 0 "register_operand" "")
(neg:DI (match_operand:DI 1 "register_operand" "")))]
@ -1847,6 +1997,45 @@
"lsr.l r0,%0,32-%1"
[(set_attr "type" "logic")])
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Integer overflow tests
;;
;; Modes QI, HI and SI are supported directly.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
(define_insn "*addv_tst<mode>"
[(set (reg:CCV R_FLAGS)
(compare:CCV (match_operand:I 0 "register_operand" "r")
(unspec:I [(match_operand:I 1 "register_operand" "%r")
(match_operand:I 2 "register_operand" "r")]
UNSPEC_ADDV)))]
"reload_completed"
"add<s> r0,%1,%2"
[(set_attr "type" "arith")])
(define_insn "*subv_tst<mode>"
[(set (reg:CCV R_FLAGS)
(compare:CCV (match_operand:I 0 "register_operand" "r")
(unspec:I [(match_operand:I 1 "reg_or_0_operand" "rO")
(match_operand:I 2 "register_operand" "r")]
UNSPEC_SUBV)))]
"reload_completed"
"sub<s> r0,%r1,%2"
[(set_attr "type" "arith")])
(define_insn "*negv_tst<mode>"
[(set (reg:CCV R_FLAGS)
(compare:CCV (match_operand:I 0 "register_operand" "r")
(unspec:I [(match_operand:I 1 "register_operand" "r")]
UNSPEC_NEGV)))]
"reload_completed"
"sub<s> r0,r0,%1"
[(set_attr "type" "arith")])
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
@ -2125,6 +2314,65 @@
}
[(set_attr "type" "cmp")])
(define_insn_and_split "*cbranch<mode>4_addv_insn"
[(set (pc)
(if_then_else (match_operator 0 "visium_equality_comparison_operator"
[(match_operand:I 1 "register_operand" "r")
(unspec:I [(match_operand:I 2 "register_operand" "%r")
(match_operand:I 3 "register_operand" "r")]
UNSPEC_ADDV)])
(label_ref (match_operand 4 ""))
(pc)))]
""
"#"
"reload_completed"
[(const_int 0)]
{
visium_split_cbranch (GET_CODE (operands[0]), XEXP (operands[0], 0),
XEXP (operands[0], 1), operands[4]);
DONE;
}
[(set_attr "type" "cmp")])
(define_insn_and_split "*cbranch<mode>4_subv_insn"
[(set (pc)
(if_then_else (match_operator 0 "visium_equality_comparison_operator"
[(match_operand:I 1 "register_operand" "r")
(unspec:I [(match_operand:I 2 "reg_or_0_operand" "rO")
(match_operand:I 3 "register_operand" "r")]
UNSPEC_SUBV)])
(label_ref (match_operand 4 ""))
(pc)))]
""
"#"
"reload_completed"
[(const_int 0)]
{
visium_split_cbranch (GET_CODE (operands[0]), XEXP (operands[0], 0),
XEXP (operands[0], 1), operands[4]);
DONE;
}
[(set_attr "type" "cmp")])
(define_insn_and_split "*cbranch<mode>4_negv_insn"
[(set (pc)
(if_then_else (match_operator 0 "visium_equality_comparison_operator"
[(match_operand:I 1 "register_operand" "r")
(unspec:I [(match_operand:I 2 "register_operand" "r")]
UNSPEC_NEGV)])
(label_ref (match_operand 3 ""))
(pc)))]
""
"#"
"reload_completed"
[(const_int 0)]
{
visium_split_cbranch (GET_CODE (operands[0]), XEXP (operands[0], 0),
XEXP (operands[0], 1), operands[3]);
DONE;
}
[(set_attr "type" "cmp")])
(define_insn_and_split "*cbranchsi4_btst_insn"
[(set (pc)
(if_then_else (match_operator 0 "visium_equality_comparison_operator"

View File

@ -1,3 +1,9 @@
2016-10-20 Eric Botcazou <ebotcazou@adacore.com>
* gcc.target/visium/overflow8.c: New.
* gcc.target/visium/overflow16.c: Likewise.
* gcc.target/visium/overflow32: Likewise.
2016-10-20 Michael Matz <matz@suse.de>
* gcc.dg/loop-split.c: New test.

View File

@ -0,0 +1,39 @@
/* { dg-do compile } */
/* { dg-options "-O2" } */
#include <stdbool.h>
bool my_uadd_overflow (unsigned short a, unsigned short b, unsigned short *res)
{
return __builtin_add_overflow (a, b, res);
}
bool my_usub_overflow (unsigned short a, unsigned short b, unsigned short *res)
{
return __builtin_sub_overflow (a, b, res);
}
bool my_uneg_overflow (unsigned short a, unsigned short *res)
{
return __builtin_sub_overflow (0, a, res);
}
bool my_add_overflow (short a, short b, short *res)
{
return __builtin_add_overflow (a, b, res);
}
bool my_sub_overflow (short a, short b, short *res)
{
return __builtin_sub_overflow (a, b, res);
}
bool my_neg_overflow (short a, short *res)
{
return __builtin_sub_overflow (0, a, res);
}
/* { dg-final { scan-assembler-times "add.w" 2 } } */
/* { dg-final { scan-assembler-times "sub.w" 4 } } */
/* { dg-final { scan-assembler-not "cmp.w" } } */
/* { dg-final { scan-assembler-not "mov.w" } } */

View File

@ -0,0 +1,39 @@
/* { dg-do compile } */
/* { dg-options "-O2" } */
#include <stdbool.h>
bool my_uadd_overflow (unsigned int a, unsigned int b, unsigned int *res)
{
return __builtin_add_overflow (a, b, res);
}
bool my_usub_overflow (unsigned int a, unsigned int b, unsigned int *res)
{
return __builtin_sub_overflow (a, b, res);
}
bool my_uneg_overflow (unsigned int a, unsigned int *res)
{
return __builtin_sub_overflow (0, a, res);
}
bool my_add_overflow (int a, int b, int *res)
{
return __builtin_add_overflow (a, b, res);
}
bool my_sub_overflow (int a, int b, int *res)
{
return __builtin_sub_overflow (a, b, res);
}
bool my_neg_overflow (int a, int *res)
{
return __builtin_sub_overflow (0, a, res);
}
/* { dg-final { scan-assembler-times "add.l" 2 } } */
/* { dg-final { scan-assembler-times "sub.l" 4 } } */
/* { dg-final { scan-assembler-not "cmp.l" } } */
/* { dg-final { scan-assembler-not "mov.l" } } */

View File

@ -0,0 +1,39 @@
/* { dg-do compile } */
/* { dg-options "-O2" } */
#include <stdbool.h>
bool my_uadd_overflow (unsigned char a, unsigned char b, unsigned char *res)
{
return __builtin_add_overflow (a, b, res);
}
bool my_usub_overflow (unsigned char a, unsigned char b, unsigned char *res)
{
return __builtin_sub_overflow (a, b, res);
}
bool my_uneg_overflow (unsigned char a, unsigned char *res)
{
return __builtin_sub_overflow (0, a, res);
}
bool my_add_overflow (signed char a, signed char b, signed char *res)
{
return __builtin_add_overflow (a, b, res);
}
bool my_sub_overflow (signed char a, signed char b, signed char *res)
{
return __builtin_sub_overflow (a, b, res);
}
bool my_neg_overflow (signed char a, signed char *res)
{
return __builtin_sub_overflow (0, a, res);
}
/* { dg-final { scan-assembler-times "add.b" 2 } } */
/* { dg-final { scan-assembler-times "sub.b" 4 } } */
/* { dg-final { scan-assembler-not "cmp.b" } } */
/* { dg-final { scan-assembler-not "mov.b" } } */