+2019-07-24 Andreas Krebbel <krebbel@linux.ibm.com>
+
+ * config/s390/predicates.md (addv_const_operand): New predicate.
+ * config/s390/s390-modes.def (CCO): New condition code mode.
+ * config/s390/s390.c (s390_match_ccmode_set): Handle E_CCOmode.
+ (s390_branch_condition_mask): Likewise.
+ * config/s390/s390.md ("addv<mode>4", "subv<mode>4")
+ ("mulv<mode>4"): New expanders.
+ ("*addv<mode>3_ccoverflow", "*addv<mode>3_ccoverflow_const")
+ ("*subv<mode>3_ccoverflow", "*mulv<mode>3_ccoverflow"): New
+ pattern definitions.
+
2019-07-24 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
PR middle-end/91166
return s390_valid_shift_count (op, 0);
}
)
+
+; An integer constant which can be used in a signed add with overflow
+; pattern without being reloaded.
+(define_predicate "addv_const_operand"
+ (and (match_code "const_int")
+ (match_test "INTVAL (op) >= -32768 && INTVAL (op) <= 32767")))
Condition Codes
+ CC0 CC1 CC2 CC3
+
Check for zero
CCZ: EQ NE NE NE
CCAP: EQ LT GT LT (AGHI, AHI)
CCAN: EQ LT GT GT (AGHI, AHI)
+Condition codes for overflow checking resulting from signed adds/subs/mults
+
+CCO: EQ EQ EQ NE (AGR, AGHI, SGR, MSC, ...)
+
Condition codes of unsigned adds and subs
CCL: EQ NE EQ NE (ALGF/R, ALG/R, AL/R/Y,
the sign of the result even in case of an overflow.
+CCO
+
+This mode is used to check whether there was an overflow condition in
+a signed add, sub, or mul operation. See (addv<mode>4, subv<mode>4,
+mulv<mode>4 patterns).
+
+
CCT, CCT1, CCT2, CCT3
If bits of an integer masked with an AND instruction are checked, the test under
CC_MODE (CCA);
CC_MODE (CCAP);
CC_MODE (CCAN);
+CC_MODE (CCO);
CC_MODE (CCL);
CC_MODE (CCL1);
CC_MODE (CCL2);
case E_CCSRmode:
case E_CCUmode:
case E_CCURmode:
+ case E_CCOmode:
case E_CCLmode:
case E_CCL1mode:
case E_CCL2mode:
}
break;
+ case E_CCOmode:
+ switch (GET_CODE (code))
+ {
+ case EQ: return CC0 | CC1 | CC2;
+ case NE: return CC3;
+ default: return -1;
+ }
+ break;
+
case E_CCSmode:
switch (GET_CODE (code))
{
"agh\t%0,%2"
[(set_attr "op_type" "RXY")])
+
+; Jump to label OP3 if OP1 + OP2 results in a signed overflow
+
+; addv_const_operand accepts all constants which can be handled
+; without reloads. These will be handled primarily by
+; "*addv<mode>3_ccoverflow_const" which doesn't provide a register
+; alternative. Hence we have to match the operand exactly.
+; For immediates we have to avoid the SIGN_EXTEND around OP2.
+(define_expand "addv<mode>4"
+ [(parallel
+ [(set (reg:CCO CC_REGNUM)
+ (compare:CCO (plus:<DBL>
+ (sign_extend:<DBL> (match_operand:GPR 1 "nonimmediate_operand"))
+ (match_dup 4))
+ (sign_extend:<DBL> (plus:GPR (match_dup 1)
+ (match_operand:GPR 2 "general_operand")))))
+ (set (match_operand:GPR 0 "nonimmediate_operand")
+ (plus:GPR (match_dup 1) (match_dup 2)))])
+ (set (pc)
+ (if_then_else (ne (reg:CCO CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 3))
+ (pc)))]
+ ""
+{
+ if (CONSTANT_P (operands[2])
+ && !addv_const_operand (operands[2], GET_MODE (operands[2])))
+ operands[2] = force_reg (<GPR:MODE>mode, operands[2]);
+
+ if (GET_MODE (operands[2]) != VOIDmode)
+ operands[4] = gen_rtx_SIGN_EXTEND (<DBL>mode, operands[2]);
+ else
+ /* This is what CSE does when propagating a constant into the pattern. */
+ operands[4] = simplify_unary_operation (SIGN_EXTEND, <GPR:DBL>mode, operands[2], <GPR:MODE>mode);
+})
+
+; ark, agrk, ar, ahi, ahik, aghik, a, ay, agr, aghi, ag, asi, agsi
+(define_insn "*addv<mode>3_ccoverflow"
+ [(set (reg CC_REGNUM)
+ (compare (plus:<DBL>
+ (sign_extend:<DBL> (match_operand:GPR 1 "nonimmediate_operand" "%0,d,0,d,0,0,0"))
+ (sign_extend:<DBL> (match_operand:GPR 2 "general_operand" " d,d,K,K,R,T,C")))
+ (sign_extend:<DBL> (plus:GPR (match_dup 1) (match_dup 2)))))
+ (set (match_operand:GPR 0 "nonimmediate_operand" "=d,d,d,d,d,d,S")
+ (plus:GPR (match_dup 1) (match_dup 2)))]
+ "s390_match_ccmode (insn, CCOmode)"
+ "@
+ a<g>r\t%0,%2
+ a<g>rk\t%0,%1,%2
+ a<g>hi\t%0,%h2
+ a<g>hik\t%0,%1,%h2
+ a<g>\t%0,%2
+ a<y>\t%0,%2
+ a<g>si\t%0,%c2"
+ [(set_attr "op_type" "RR<E>,RRF,RI,RIE,RX<Y>,RXY,SIY")
+ (set_attr "cpu_facility" "*,z196,*,z196,*,longdisp,z10")
+ (set_attr "z10prop" "z10_super_E1,*,z10_super_E1,*,
+ z10_super_E1,z10_super_E1,z10_super_E1")])
+
+; ahi, aghi, ahik, aghik, asi, agsi
+(define_insn "*addv<mode>3_ccoverflow_const"
+ [(set (reg CC_REGNUM)
+ (compare (plus:<DBL>
+ (sign_extend:<DBL> (match_operand:GPR 1 "nonimmediate_operand" "%0,d,0"))
+ (match_operand:<DBL> 2 "addv_const_operand" "K,K,C"))
+ (sign_extend:<DBL> (plus:GPR (match_dup 1) (match_dup 2)))))
+ (set (match_operand:GPR 0 "nonimmediate_operand" "=d,d,S")
+ (plus:GPR (match_dup 1) (match_dup 2)))]
+ "s390_match_ccmode (insn, CCOmode)"
+ "@
+ a<g>hi\t%0,%h2
+ a<g>hik\t%0,%1,%h2
+ a<g>si\t%0,%c2"
+ [(set_attr "op_type" "RI,RIE,SIY")
+ (set_attr "cpu_facility" "*,z196,z10")
+ (set_attr "z10prop" "z10_super_E1,*,z10_super_E1")])
+
+
;
; add(tf|df|sf|td|dd)3 instruction pattern(s).
;
"sgh\t%0,%2"
[(set_attr "op_type" "RXY")])
+; Jump to label OP3 if OP1 - OP2 results in a signed overflow
+(define_expand "subv<mode>4"
+ [(parallel
+ [(set (reg:CCO CC_REGNUM)
+ (compare:CCO (minus:<DBL>
+ (sign_extend:<DBL> (match_operand:GPR 1 "nonimmediate_operand"))
+ (sign_extend:<DBL> (match_operand:GPR 2 "nonimmediate_operand")))
+ (sign_extend:<DBL> (minus:GPR (match_dup 1) (match_dup 2)))))
+ (set (match_operand:GPR 0 "nonimmediate_operand")
+ (minus:GPR (match_dup 1) (match_dup 2)))])
+ (set (pc)
+ (if_then_else (ne (reg:CCO CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 3))
+ (pc)))]
+ "")
+
+; sr, s, sy, sgr, sg, srk, sgrk
+(define_insn "*subv<mode>3_ccoverflow"
+ [(set (reg CC_REGNUM)
+ (compare (minus:<DBL>
+ (sign_extend:<DBL> (match_operand:GPR 1 "nonimmediate_operand" "0,d,0,0"))
+ (sign_extend:<DBL> (match_operand:GPR 2 "nonimmediate_operand" "d,d,R,T")))
+ (sign_extend:<DBL> (minus:GPR (match_dup 1) (match_dup 2)))))
+ (set (match_operand:GPR 0 "register_operand" "=d,d,d,d")
+ (minus:GPR (match_dup 1) (match_dup 2)))]
+ "s390_match_ccmode (insn, CCOmode)"
+ "@
+ s<g>r\t%0,%2
+ s<g>rk\t%0,%1,%2
+ s<g>\t%0,%2
+ s<y>\t%0,%2"
+ [(set_attr "op_type" "RR<E>,RRF,RX<Y>,RXY")
+ (set_attr "cpu_facility" "*,z196,*,longdisp")
+ (set_attr "z10prop" "z10_super_c_E1,*,z10_super_E1,z10_super_E1")])
+
;
; sub(tf|df|sf|td|dd)3 instruction pattern(s).
(set_attr "type" "imulsi")
(set_attr "cpu_facility" "*,*,z10")])
+; Jump to label OP3 if OP1 * OP2 results in a signed overflow
+(define_expand "mulv<mode>4"
+ [(parallel
+ [(set (reg:CCO CC_REGNUM)
+ (compare:CCO (mult:<DBL>
+ (sign_extend:<DBL> (match_operand:GPR 1 "register_operand"))
+ (sign_extend:<DBL> (match_operand:GPR 2 "nonimmediate_operand")))
+ (sign_extend:<DBL> (mult:GPR (match_dup 1) (match_dup 2)))))
+ (set (match_operand:GPR 0 "register_operand")
+ (mult:GPR (match_dup 1) (match_dup 2)))])
+ (set (pc)
+ (if_then_else (ne (reg:CCO CC_REGNUM) (const_int 0))
+ (label_ref (match_operand 3))
+ (pc)))]
+ "TARGET_Z14")
+
+; msrkc, msc, msgrkc, msgc
+(define_insn "*mulv<mode>3_ccoverflow"
+ [(set (reg CC_REGNUM)
+ (compare (mult:<DBL>
+ (sign_extend:<DBL> (match_operand:GPR 1 "register_operand" "%d,0"))
+ (sign_extend:<DBL> (match_operand:GPR 2 "nonimmediate_operand" " d,T")))
+ (sign_extend:<DBL> (mult:GPR (match_dup 1) (match_dup 2)))))
+ (set (match_operand:GPR 0 "register_operand" "=d,d")
+ (mult:GPR (match_dup 1) (match_dup 2)))]
+ "s390_match_ccmode (insn, CCOmode) && TARGET_Z14"
+ "@
+ ms<g>rkc\t%0,%1,%2
+ ms<g>c\t%0,%2"
+ [(set_attr "op_type" "RRF,RXY")])
+
+
;
; umul instruction pattern(s).
;
+2019-07-24 Andreas Krebbel <krebbel@linux.ibm.com>
+
+ * gcc.target/s390/addsub-signed-overflow-1.c: New test.
+ * gcc.target/s390/addsub-signed-overflow-2.c: New test.
+ * gcc.target/s390/mul-signed-overflow-1.c: New test.
+ * gcc.target/s390/mul-signed-overflow-2.c: New test.
+
2019-07-24 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
PR middle-end/91166
--- /dev/null
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch --save-temps" } */
+
+#include <stddef.h>
+#include <limits.h>
+
+int __attribute__((noinline,noclone))
+sadd (int a, int b, int *res)
+{
+ return __builtin_sadd_overflow(a, b, res);
+}
+
+int __attribute__((noinline,noclone))
+ssub (int a, int b, int *res)
+{
+ return __builtin_ssub_overflow(a, b, res);
+}
+
+
+int __attribute__((noinline,noclone))
+saddl (long a, long b, long *res)
+{
+ return __builtin_saddl_overflow(a, b, res);
+}
+
+int __attribute__((noinline,noclone))
+ssubl (long a, long b, long *res)
+{
+ return __builtin_ssubl_overflow(a, b, res);
+}
+
+
+int __attribute__((noinline,noclone))
+saddll (long long a, long long b, long long *res)
+{
+ return __builtin_saddll_overflow(a, b, res);
+}
+
+int __attribute__((noinline,noclone))
+ssubll (long long a, long long b, long long *res)
+{
+ return __builtin_ssubll_overflow(a, b, res);
+}
+
+
+/* With the attribute at least main always uses the same instructions
+ regardless of the -march setting. This is necessary for the
+ scan-assembler-times directive below. */
+int __attribute__ ((target("arch=z10")))
+main ()
+{
+ int ret = 0;
+ int result;
+ long lresult;
+ long long llresult;
+
+ ret += !!sadd (INT_MAX, 1, &result);
+ ret += !!ssub (INT_MIN, 1, &result);
+ ret += !!saddl (LONG_MAX, 1, &lresult);
+ ret += !!ssubl (LONG_MIN, 1, &lresult);
+ ret += !!saddll (LLONG_MAX, 1, &llresult);
+ ret += !!ssubll (LLONG_MIN, 1, &llresult);
+
+ if (ret != 6)
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* Check that no compare or bitop instructions are emitted. */
+/* { dg-final { scan-assembler-not "\tcr" } } */
+/* { dg-final { scan-assembler-not "\txr" } } */
+/* { dg-final { scan-assembler-not "\tnr" } } */
+/* { dg-final { scan-assembler-not "\tcgr" } } */
+/* { dg-final { scan-assembler-not "\txgr" } } */
+/* { dg-final { scan-assembler-not "\tngr" } } */
+/* On 31 bit the long long variants use risbgn to merge the 32 bit
+ regs into a 64 bit reg. */
+/* { dg-final { scan-assembler-not "\trisbg" { target { lp64 } } } } */
+/* Just one for the ret != 6 comparison. */
+/* { dg-final { scan-assembler-times "ci" 1 } } */
--- /dev/null
+/* { dg-do run } */
+/* { dg-options "-O3 -mzarch --save-temps" } */
+
+#include <stddef.h>
+#include <limits.h>
+
+int __attribute__((noinline,noclone))
+sadd (int a, int *res)
+{
+ return __builtin_sadd_overflow(a, -1, res);
+}
+
+int __attribute__((noinline,noclone))
+ssub (int a, int *res)
+{
+ return __builtin_ssub_overflow(a, -1, res);
+}
+
+
+int __attribute__((noinline,noclone))
+saddl (long a, long *res)
+{
+ return __builtin_saddl_overflow(a, -1, res);
+}
+
+int __attribute__((noinline,noclone))
+ssubl (long a, long *res)
+{
+ return __builtin_ssubl_overflow(a, -1, res);
+}
+
+
+int __attribute__((noinline,noclone))
+saddll (long long a, long long *res)
+{
+ return __builtin_saddll_overflow(a, -1, res);
+}
+
+int __attribute__((noinline,noclone))
+ssubll (long long a, long long *res)
+{
+ return __builtin_ssubll_overflow(a, -1, res);
+}
+
+/* With the attribute at least main always uses the same instructions
+ regardless of the -march setting. This is necessary for the
+ scan-assembler-times directive below. */
+int __attribute__ ((target("arch=z10")))
+main ()
+{
+ int ret = 0;
+ int result;
+ long lresult;
+ long long llresult;
+
+ ret += !!sadd (INT_MIN, &result);
+ ret += !!ssub (INT_MIN, &result);
+ ret += !!saddl (LONG_MIN, &lresult);
+ ret += !!ssubl (LONG_MIN, &lresult);
+ ret += !!saddll (LLONG_MIN, &llresult);
+ ret += !!ssubll (LLONG_MIN, &llresult);
+
+ if (ret != 3)
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* Check that no compare or bitop instructions are emitted. */
+/* { dg-final { scan-assembler-not "\tcr" } } */
+/* { dg-final { scan-assembler-not "\txr" } } */
+/* { dg-final { scan-assembler-not "\tnr" } } */
+/* { dg-final { scan-assembler-not "\tcgr" } } */
+/* { dg-final { scan-assembler-not "\txgr" } } */
+/* { dg-final { scan-assembler-not "\tngr" } } */
+/* On 31 bit the long long variants use risbgn to merge the 32 bit
+ regs into a 64 bit reg. */
+/* { dg-final { scan-assembler-not "\trisbg" { target { lp64 } } } } */
+/* Just one for the ret != 3 comparison. */
+/* { dg-final { scan-assembler-times "ci" 1 } } */
--- /dev/null
+/* { dg-do run } */
+/* z14 only because we need msrkc, msc, msgrkc, msgc */
+/* { dg-options "-O3 -march=z14 -mzarch --save-temps" } */
+
+#include <stddef.h>
+#include <limits.h>
+
+int __attribute__((noinline,noclone))
+smul (int a, int b, int *res)
+{
+ return __builtin_smul_overflow(a, b, res);
+}
+
+int __attribute__((noinline,noclone))
+smull (long a, long b, long *res)
+{
+ return __builtin_smull_overflow(a, b, res);
+}
+
+int __attribute__((noinline,noclone))
+smulll (long long a, long long b, long long *res)
+{
+ return __builtin_smulll_overflow(a, b, res);
+}
+
+
+int
+main ()
+{
+ int ret = 0;
+ int result;
+ long lresult;
+ long long llresult;
+
+ ret += !!smul (INT_MAX, 2, &result);
+ ret += !!smull (LONG_MAX, 2, &lresult);
+ ret += !!smulll (LLONG_MAX, 2, &llresult);
+
+ if (ret != 3)
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* Check that no compare or bitop instructions are emitted. */
+/* { dg-final { scan-assembler-not "\tcr" } } */
+/* { dg-final { scan-assembler-not "\txr" } } */
+/* { dg-final { scan-assembler-not "\tnr" } } */
+/* { dg-final { scan-assembler-not "\tcgr" } } */
+/* { dg-final { scan-assembler-not "\txgr" } } */
+/* { dg-final { scan-assembler-not "\tngr" } } */
+/* On 31 bit the long long variants use risbgn to merge the 32 bit
+ regs into a 64 bit reg. */
+/* { dg-final { scan-assembler-not "\trisbg" { target { lp64 } } } } */
+/* Just one for the ret != 3 comparison. */
+/* { dg-final { scan-assembler-times "ci" 1 } } */
--- /dev/null
+/* { dg-do run } */
+/* z14 only because we need msrkc, msc, msgrkc, msgc */
+/* { dg-options "-O3 -march=z14 -mzarch --save-temps" } */
+
+#include <stddef.h>
+#include <limits.h>
+
+int __attribute__((noinline,noclone))
+smul (int a, int *res)
+{
+ return __builtin_smul_overflow(a, -1, res);
+}
+
+int __attribute__((noinline,noclone))
+smull (long a, long *res)
+{
+ return __builtin_smull_overflow(a, -1, res);
+}
+
+int __attribute__((noinline,noclone))
+smulll (long long a, long long *res)
+{
+ return __builtin_smulll_overflow(a, -1, res);
+}
+
+
+int
+main ()
+{
+ int ret = 0;
+ int result;
+ long lresult;
+ long long llresult;
+
+ ret += !!smul (INT_MIN, &result);
+ ret += !!smull (LONG_MIN, &lresult);
+ ret += !!smulll (LLONG_MIN, &llresult);
+
+ if (ret != 3)
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* Check that no compare or bitop instructions are emitted. */
+/* { dg-final { scan-assembler-not "\tcr" } } */
+/* { dg-final { scan-assembler-not "\txr" } } */
+/* { dg-final { scan-assembler-not "\tnr" } } */
+/* { dg-final { scan-assembler-not "\tcgr" } } */
+/* { dg-final { scan-assembler-not "\txgr" } } */
+/* { dg-final { scan-assembler-not "\tngr" } } */
+/* On 31 bit the long long variants use risbgn to merge the 32 bit
+ regs into a 64 bit reg. */
+/* { dg-final { scan-assembler-not "\trisbg" { target { lp64 } } } } */
+/* Just one for the ret != 3 comparison. */
+/* { dg-final { scan-assembler-times "ci" 1 } } */