;; Subtract with jump on overflow.
(define_expand "subv<mode>4"
[(parallel [(set (reg:CCO FLAGS_REG)
- (eq:CCO (minus:<DWI>
- (sign_extend:<DWI>
- (match_operand:SWI 1 "nonimmediate_operand"))
- (match_dup 4))
- (sign_extend:<DWI>
- (minus:SWI (match_dup 1)
- (match_operand:SWI 2
- "<general_operand>")))))
- (set (match_operand:SWI 0 "register_operand")
- (minus:SWI (match_dup 1) (match_dup 2)))])
+ (eq:CCO
+ (minus:<DWI>
+ (sign_extend:<DWI>
+ (match_operand:SWIDWI 1 "nonimmediate_operand"))
+ (match_dup 4))
+ (sign_extend:<DWI>
+ (minus:SWIDWI (match_dup 1)
+ (match_operand:SWIDWI 2
+ "<general_hilo_operand>")))))
+ (set (match_operand:SWIDWI 0 "register_operand")
+ (minus:SWIDWI (match_dup 1) (match_dup 2)))])
(set (pc) (if_then_else
(eq (reg:CCO FLAGS_REG) (const_int 0))
(label_ref (match_operand 3))
""
{
ix86_fixup_binary_operands_no_copy (MINUS, <MODE>mode, operands);
- if (CONST_INT_P (operands[2]))
+ if (CONST_SCALAR_INT_P (operands[2]))
operands[4] = operands[2];
else
operands[4] = gen_rtx_SIGN_EXTEND (<DWI>mode, operands[2]);
[(set_attr "type" "alu")
(set_attr "mode" "<MODE>")])
-(define_insn "*subv<mode>4_1"
+(define_insn "subv<mode>4_1"
[(set (reg:CCO FLAGS_REG)
(eq:CCO (minus:<DWI>
(sign_extend:<DWI>
(const_string "4")]
(const_string "<MODE_SIZE>")))])
+(define_insn_and_split "*subv<dwi>4_doubleword"
+ [(set (reg:CCO FLAGS_REG)
+ (eq:CCO
+ (minus:<QWI>
+ (sign_extend:<QWI>
+ (match_operand:<DWI> 1 "nonimmediate_operand" "0,0"))
+ (sign_extend:<QWI>
+ (match_operand:<DWI> 2 "x86_64_hilo_general_operand" "r<di>,o")))
+ (sign_extend:<QWI>
+ (minus:<DWI> (match_dup 1) (match_dup 2)))))
+ (set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro,r")
+ (minus:<DWI> (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (MINUS, <MODE>mode, operands)"
+ "#"
+ "reload_completed"
+ [(parallel [(set (reg:CC FLAGS_REG)
+ (compare:CC (match_dup 1) (match_dup 2)))
+ (set (match_dup 0)
+ (minus:DWIH (match_dup 1) (match_dup 2)))])
+ (parallel [(set (reg:CCO FLAGS_REG)
+ (eq:CCO
+ (minus:<DWI>
+ (minus:<DWI>
+ (sign_extend:<DWI> (match_dup 4))
+ (ltu:<DWI> (reg:CC FLAGS_REG) (const_int 0)))
+ (sign_extend:<DWI> (match_dup 5)))
+ (sign_extend:<DWI>
+ (minus:DWIH
+ (minus:DWIH
+ (match_dup 4)
+ (ltu:DWIH (reg:CC FLAGS_REG) (const_int 0)))
+ (match_dup 5)))))
+ (set (match_dup 3)
+ (minus:DWIH
+ (minus:DWIH
+ (match_dup 4)
+ (ltu:DWIH (reg:CC FLAGS_REG) (const_int 0)))
+ (match_dup 5)))])]
+{
+ split_double_mode (<DWI>mode, &operands[0], 3, &operands[0], &operands[3]);
+})
+
+(define_insn_and_split "*subv<dwi>4_doubleword_1"
+ [(set (reg:CCO FLAGS_REG)
+ (eq:CCO
+ (minus:<QWI>
+ (sign_extend:<QWI>
+ (match_operand:<DWI> 1 "nonimmediate_operand" "0"))
+ (match_operand:<QWI> 3 "const_scalar_int_operand" ""))
+ (sign_extend:<QWI>
+ (minus:<DWI>
+ (match_dup 1)
+ (match_operand:<DWI> 2 "x86_64_hilo_general_operand" "<di>")))))
+ (set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro")
+ (minus:<DWI> (match_dup 1) (match_dup 2)))]
+ "ix86_binary_operator_ok (MINUS, <MODE>mode, operands)
+ && CONST_SCALAR_INT_P (operands[2])
+ && rtx_equal_p (operands[2], operands[3])"
+ "#"
+ "reload_completed"
+ [(parallel [(set (reg:CC FLAGS_REG)
+ (compare:CC (match_dup 1) (match_dup 2)))
+ (set (match_dup 0)
+ (minus:DWIH (match_dup 1) (match_dup 2)))])
+ (parallel [(set (reg:CCO FLAGS_REG)
+ (eq:CCO
+ (minus:<DWI>
+ (minus:<DWI>
+ (sign_extend:<DWI> (match_dup 4))
+ (ltu:<DWI> (reg:CC FLAGS_REG) (const_int 0)))
+ (match_dup 5))
+ (sign_extend:<DWI>
+ (minus:DWIH
+ (minus:DWIH
+ (match_dup 4)
+ (ltu:DWIH (reg:CC FLAGS_REG) (const_int 0)))
+ (match_dup 5)))))
+ (set (match_dup 3)
+ (minus:DWIH
+ (minus:DWIH
+ (match_dup 4)
+ (ltu:DWIH (reg:CC FLAGS_REG) (const_int 0)))
+ (match_dup 5)))])]
+{
+ split_double_mode (<DWI>mode, &operands[0], 3, &operands[0], &operands[3]);
+ if (operands[2] == const0_rtx)
+ {
+ emit_insn (gen_subv<mode>4_1 (operands[3], operands[4], operands[5],
+ operands[5]));
+ DONE;
+ }
+})
+
+(define_insn "*subv<mode>4_overflow_1"
+ [(set (reg:CCO FLAGS_REG)
+ (eq:CCO
+ (minus:<DWI>
+ (minus:<DWI>
+ (sign_extend:<DWI>
+ (match_operand:SWI 1 "nonimmediate_operand" "%0,0"))
+ (match_operator:<DWI> 4 "ix86_carry_flag_operator"
+ [(match_operand 3 "flags_reg_operand") (const_int 0)]))
+ (sign_extend:<DWI>
+ (match_operand:SWI 2 "<general_sext_operand>" "rWe,m")))
+ (sign_extend:<DWI>
+ (minus:SWI
+ (minus:SWI
+ (match_dup 1)
+ (match_operator:SWI 5 "ix86_carry_flag_operator"
+ [(match_dup 3) (const_int 0)]))
+ (match_dup 2)))))
+ (set (match_operand:SWI 0 "nonimmediate_operand" "=rm,r")
+ (minus:SWI
+ (minus:SWI
+ (match_dup 1)
+ (match_op_dup 5 [(match_dup 3) (const_int 0)]))
+ (match_dup 2)))]
+ "ix86_binary_operator_ok (MINUS, <MODE>mode, operands)"
+ "sbb{<imodesuffix>}\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "*subv<mode>4_overflow_2"
+ [(set (reg:CCO FLAGS_REG)
+ (eq:CCO
+ (minus:<DWI>
+ (minus:<DWI>
+ (sign_extend:<DWI>
+ (match_operand:SWI 1 "nonimmediate_operand" "%0"))
+ (match_operator:<DWI> 4 "ix86_carry_flag_operator"
+ [(match_operand 3 "flags_reg_operand") (const_int 0)]))
+ (match_operand:<DWI> 6 "const_int_operand" ""))
+ (sign_extend:<DWI>
+ (minus:SWI
+ (minus:SWI
+ (match_dup 1)
+ (match_operator:SWI 5 "ix86_carry_flag_operator"
+ [(match_dup 3) (const_int 0)]))
+ (match_operand:SWI 2 "x86_64_immediate_operand" "e")))))
+ (set (match_operand:SWI 0 "nonimmediate_operand" "=rm")
+ (minus:SWI
+ (minus:SWI
+ (match_dup 1)
+ (match_op_dup 5 [(match_dup 3) (const_int 0)]))
+ (match_dup 2)))]
+ "ix86_binary_operator_ok (MINUS, <MODE>mode, operands)
+ && CONST_INT_P (operands[2])
+ && INTVAL (operands[2]) == INTVAL (operands[6])"
+ "sbb{<imodesuffix>}\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")
+ (set_attr "mode" "<MODE>")
+ (set (attr "length_immediate")
+ (if_then_else (match_test "IN_RANGE (INTVAL (operands[2]), -128, 127)")
+ (const_string "1")
+ (const_string "4")))])
+
(define_expand "usubv<mode>4"
[(parallel [(set (reg:CC FLAGS_REG)
(compare:CC
/* { dg-do compile } */
/* { dg-options "-O2 -masm=att" } */
/* { dg-final { scan-assembler-not "cmp\[lq]\t" } } */
-/* { dg-final { scan-assembler-times "setc\t%" 3 } } */
-/* { dg-final { scan-assembler-times "seto\t%" 5 } } */
-/* { dg-final { scan-assembler-times "adc\[lq]\t" 5 } } */
+/* { dg-final { scan-assembler-times "setc\t%" 5 } } */
+/* { dg-final { scan-assembler-times "seto\t%" 7 } } */
+/* { dg-final { scan-assembler-times "adc\[lq]\t" 9 } } */
#ifdef __x86_64__
typedef unsigned __int128 U;
+typedef unsigned long long HU;
typedef signed __int128 S;
#else
typedef unsigned long long U;
+typedef unsigned int HU;
typedef signed long long S;
#endif
int o;
| (S) 0xbeedead, &z);
return z;
}
+
+S
+waldo (S x)
+{
+ S z;
+ o = __builtin_add_overflow (x, (S) ((((S) 0xdeadbee) << (sizeof (S) * __CHAR_BIT__ / 2))
+ | -(HU) 0xbeedead), &z);
+ return z;
+}
+
+S
+fred (S x)
+{
+ S z;
+ o = __builtin_add_overflow (x, (S) ((-(((S) 0xdeadbee) << (sizeof (S) * __CHAR_BIT__ / 2)))
+ | -(HU) 0xbeedead), &z);
+ return z;
+}
+
+U
+plugh (U x)
+{
+ U z;
+ o = __builtin_add_overflow (x, (U) ((((U) 0xdeadbee) << (sizeof (U) * __CHAR_BIT__ / 2))
+ | -(HU) 0xbeedead), &z);
+ return z;
+}
+
+U
+xyzzy (U x)
+{
+ U z;
+ o = __builtin_add_overflow (x, (U) ((-(((U) 0xdeadbee) << (sizeof (U) * __CHAR_BIT__ / 2)))
+ | -(HU) 0xbeedead), &z);
+ return z;
+}
--- /dev/null
+/* PR target/93141 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-final { scan-assembler-not "cmp\[lq]\t" } } */
+/* { dg-final { scan-assembler-not "adc\[lq]\t" } } */
+/* { dg-final { scan-assembler-times "seto\t%" 7 } } */
+/* { dg-final { scan-assembler-times "sbb\[lq]\t" 5 } } */
+
+#ifdef __x86_64__
+typedef unsigned __int128 U;
+typedef unsigned long long HU;
+typedef signed __int128 S;
+#else
+typedef unsigned long long U;
+typedef signed int HU;
+typedef signed long long S;
+#endif
+int o;
+
+S
+qux (S x, S y)
+{
+ S z;
+ o = __builtin_sub_overflow (x, y, &z);
+ return z;
+}
+
+S
+quux (S x)
+{
+ S z;
+ o = __builtin_sub_overflow (x, ((S) 0xdeadbee) << (sizeof (S) * __CHAR_BIT__ / 2), &z);
+ return z;
+}
+
+S
+corge (S x)
+{
+ S z;
+ o = __builtin_sub_overflow (x, (((S) 0xdeadbee) << (sizeof (S) * __CHAR_BIT__ / 2))
+ | (S) 0xbeedead, &z);
+ return z;
+}
+
+S
+grault (S x)
+{
+ S z;
+ o = __builtin_sub_overflow (x, -((S) 0xdeadbee) << (sizeof (S) * __CHAR_BIT__ / 2), &z);
+ return z;
+}
+
+S
+garply (S x)
+{
+ S z;
+ o = __builtin_sub_overflow (x, (-(((S) 0xdeadbee) << (sizeof (S) * __CHAR_BIT__ / 2)))
+ | (S) 0xbeedead, &z);
+ return z;
+}
+
+S
+waldo (S x)
+{
+ S z;
+ o = __builtin_sub_overflow (x, (S) ((((S) 0xdeadbee) << (sizeof (S) * __CHAR_BIT__ / 2))
+ | -(HU) 0xbeedead), &z);
+ return z;
+}
+
+S
+fred (S x)
+{
+ S z;
+ o = __builtin_sub_overflow (x, (S) ((-(((S) 0xdeadbee) << (sizeof (S) * __CHAR_BIT__ / 2)))
+ | -(HU) 0xbeedead), &z);
+ return z;
+}