aarch64.md (subv<GPI>4, [...]): New patterns.
authorMichael Collison <michael.collison@arm.com>
Thu, 19 Jul 2018 20:24:47 +0000 (20:24 +0000)
committerMichael Collison <collison@gcc.gnu.org>
Thu, 19 Jul 2018 20:24:47 +0000 (20:24 +0000)
2018-07-19  Michael Collison  <michael.collison@arm.com>
    Richard Henderson <rth@redhat.com>

* config/aarch64/aarch64.md (subv<GPI>4, usubv<GPI>4): New patterns.
(subti): Handle op1 zero.
(subvti4, usub4ti4): New.
(*sub<GPI>3_compare1_imm): New.
(sub<GPI>3_carryinCV): New.
(*sub<GPI>3_carryinCV_z1_z2, *sub<GPI>3_carryinCV_z1): New.
(*sub<GPI>3_carryinCV_z2, *sub<GPI>3_carryinCV): New.

2018-07-19  Michael Collison  <michael.collison@arm.com>
    Richard Henderson <rth@redhat.com>

* config/aarch64/aarch64.md: (addv<GPI>4, uaddv<GPI>4): New.
(addti3): Create simpler code if low part is already known to be 0.
(addvti4, uaddvti4): New.
(*add<GPI>3_compareC_cconly_imm): New.
(*add<GPI>3_compareC_cconly): New.
(*add<GPI>3_compareC_imm): New.
(*add<GPI>3_compareC): Rename from add<GPI>3_compare1; do not
handle constants within this pattern..
(*add<GPI>3_compareV_cconly_imm): New.
(*add<GPI>3_compareV_cconly): New.
(*add<GPI>3_compareV_imm): New.
(add<GPI>3_compareV): New.
(add<GPI>3_carryinC, add<GPI>3_carryinV): New.
(*add<GPI>3_carryinC_zero, *add<GPI>3_carryinV_zero): New.
(*add<GPI>3_carryinC, *add<GPI>3_carryinV): New.
((*add<GPI>3_compareC_cconly_imm): Replace 'ne' operator
with 'comparison' operator.
(*add<GPI>3_compareV_cconly_imm): Ditto.
(*add<GPI>3_compareV_cconly): Ditto.
(*add<GPI>3_compareV_imm): Ditto.
(add<GPI>3_compareV): Ditto.
(add<mode>3_carryinC): Ditto.
(*add<mode>3_carryinC_zero): Ditto.
(*add<mode>3_carryinC): Ditto.
(add<mode>3_carryinV): Ditto.
(*add<mode>3_carryinV_zero): Ditto.
(*add<mode>3_carryinV): Ditto.

2018-07-19  Michael Collison  <michael.collison@arm.com>
    Richard Henderson <rth@redhat.com>

* config/aarch64/aarch64-modes.def (CC_V): New.
* config/aarch64/aarch64-protos.h
(aarch64_addti_scratch_regs): Declare
(aarch64_subvti_scratch_regs): Declare.
(aarch64_expand_subvti): Declare.
(aarch64_gen_unlikely_cbranch): Declare
* config/aarch64/aarch64.c (aarch64_select_cc_mode): Test
for signed overflow using CC_Vmode.
(aarch64_get_condition_code_1): Handle CC_Vmode.
(aarch64_gen_unlikely_cbranch): New function.
(aarch64_addti_scratch_regs): New function.
(aarch64_subvti_scratch_regs): New function.
(aarch64_expand_subvti): New function.

2018-07-19  Michael Collison  <michael.collison@arm.com>
    Richard Henderson <rth@redhat.com>

* gcc.target/aarch64/builtin_sadd_128.c: New testcase.
* gcc.target/aarch64/builtin_saddl.c: New testcase.
* gcc.target/aarch64/builtin_saddll.c: New testcase.
* gcc.target/aarch64/builtin_uadd_128.c: New testcase.
* gcc.target/aarch64/builtin_uaddl.c: New testcase.
* gcc.target/aarch64/builtin_uaddll.c: New testcase.
* gcc.target/aarch64/builtin_ssub_128.c: New testcase.
* gcc.target/aarch64/builtin_ssubl.c: New testcase.
* gcc.target/aarch64/builtin_ssubll.c: New testcase.
* gcc.target/aarch64/builtin_usub_128.c: New testcase.
* gcc.target/aarch64/builtin_usubl.c: New testcase.
* gcc.target/aarch64/builtin_usubll.c: New testcase.

Co-Authored-By: Richard Henderson <rth@redhat.com>
From-SVN: r262890

18 files changed:
gcc/ChangeLog
gcc/config/aarch64/aarch64-modes.def
gcc/config/aarch64/aarch64-protos.h
gcc/config/aarch64/aarch64.c
gcc/config/aarch64/aarch64.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/aarch64/builtin_sadd_128.c [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/builtin_saddl.c [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/builtin_saddll.c [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/builtin_ssub_128.c [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/builtin_ssubl.c [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/builtin_ssubll.c [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/builtin_uadd_128.c [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/builtin_uaddl.c [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/builtin_uaddll.c [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/builtin_usub_128.c [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/builtin_usubl.c [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/builtin_usubll.c [new file with mode: 0644]

index 0c998afe459cdcb448a86bd553220a4be302b7af..bb4ed8e3e919e8af07504aa5c4379c3dd5b0a220 100644 (file)
@@ -1,3 +1,62 @@
+2018-07-19  Michael Collison  <michael.collison@arm.com>
+           Richard Henderson <rth@redhat.com>
+
+       * config/aarch64/aarch64.md (subv<GPI>4, usubv<GPI>4): New patterns.
+       (subti): Handle op1 zero.
+       (subvti4, usub4ti4): New.
+       (*sub<GPI>3_compare1_imm): New.
+       (sub<GPI>3_carryinCV): New.
+       (*sub<GPI>3_carryinCV_z1_z2, *sub<GPI>3_carryinCV_z1): New.
+       (*sub<GPI>3_carryinCV_z2, *sub<GPI>3_carryinCV): New.
+
+2018-07-19  Michael Collison  <michael.collison@arm.com>
+           Richard Henderson <rth@redhat.com>
+
+       * config/aarch64/aarch64.md: (addv<GPI>4, uaddv<GPI>4): New.
+       (addti3): Create simpler code if low part is already known to be 0.
+       (addvti4, uaddvti4): New.
+       (*add<GPI>3_compareC_cconly_imm): New.
+       (*add<GPI>3_compareC_cconly): New.
+       (*add<GPI>3_compareC_imm): New.
+       (*add<GPI>3_compareC): Rename from add<GPI>3_compare1; do not
+       handle constants within this pattern..
+       (*add<GPI>3_compareV_cconly_imm): New.
+       (*add<GPI>3_compareV_cconly): New.
+       (*add<GPI>3_compareV_imm): New.
+       (add<GPI>3_compareV): New.
+       (add<GPI>3_carryinC, add<GPI>3_carryinV): New.
+       (*add<GPI>3_carryinC_zero, *add<GPI>3_carryinV_zero): New.
+       (*add<GPI>3_carryinC, *add<GPI>3_carryinV): New.
+       ((*add<GPI>3_compareC_cconly_imm): Replace 'ne' operator
+       with 'comparison' operator.
+       (*add<GPI>3_compareV_cconly_imm): Ditto.
+       (*add<GPI>3_compareV_cconly): Ditto.
+       (*add<GPI>3_compareV_imm): Ditto.
+       (add<GPI>3_compareV): Ditto.
+       (add<mode>3_carryinC): Ditto.
+       (*add<mode>3_carryinC_zero): Ditto.
+       (*add<mode>3_carryinC): Ditto.
+       (add<mode>3_carryinV): Ditto.
+       (*add<mode>3_carryinV_zero): Ditto.
+       (*add<mode>3_carryinV): Ditto.
+
+2018-07-19  Michael Collison  <michael.collison@arm.com>
+           Richard Henderson <rth@redhat.com>
+
+       * config/aarch64/aarch64-modes.def (CC_V): New.
+       * config/aarch64/aarch64-protos.h
+       (aarch64_addti_scratch_regs): Declare
+       (aarch64_subvti_scratch_regs): Declare.
+       (aarch64_expand_subvti): Declare.
+       (aarch64_gen_unlikely_cbranch): Declare
+       * config/aarch64/aarch64.c (aarch64_select_cc_mode): Test
+       for signed overflow using CC_Vmode.
+       (aarch64_get_condition_code_1): Handle CC_Vmode.
+       (aarch64_gen_unlikely_cbranch): New function.
+       (aarch64_addti_scratch_regs): New function.
+       (aarch64_subvti_scratch_regs): New function.
+       (aarch64_expand_subvti): New function.
+
 2018-07-19  Andre Vieira  <andre.simoesdiasvieira@arm.com>
 
        * config/aarch64/aarch64-option-extensions.def: New entry for profile
index 1a05b6cc70828ce929c39ef6197b50ee5589e058..ea7ecc2d5e4ce18d2ff25862cc9eb998a169a9cd 100644 (file)
@@ -24,6 +24,7 @@ CC_MODE (CC_SWP);
 CC_MODE (CC_NZ);    /* Only N and Z bits of condition flags are valid.  */
 CC_MODE (CC_Z);     /* Only Z bit of condition flags is valid.  */
 CC_MODE (CC_C);     /* Only C bit of condition flags is valid.  */
+CC_MODE (CC_V);     /* Only V bit of condition flags is valid.  */
 
 /* Half-precision floating point for __fp16.  */
 FLOAT_MODE (HF, 2, 0);
index 5d07583cce34813654b84f597269fab6b265413c..af5db9c595385f7586692258f750b6aceb3ed9c8 100644 (file)
@@ -472,6 +472,16 @@ void aarch64_relayout_simd_types (void);
 void aarch64_reset_previous_fndecl (void);
 bool aarch64_return_address_signing_enabled (void);
 void aarch64_save_restore_target_globals (tree);
+void aarch64_addti_scratch_regs (rtx, rtx, rtx *,
+                                rtx *, rtx *,
+                                rtx *, rtx *,
+                                rtx *);
+void aarch64_subvti_scratch_regs (rtx, rtx, rtx *,
+                                 rtx *, rtx *,
+                                 rtx *, rtx *, rtx *);
+void aarch64_expand_subvti (rtx, rtx, rtx,
+                           rtx, rtx, rtx, rtx);
+
 
 /* Initialize builtins for SIMD intrinsics.  */
 void init_aarch64_simd_builtins (void);
@@ -498,7 +508,8 @@ void aarch64_split_simd_move (rtx, rtx);
 bool aarch64_float_const_representable_p (rtx);
 
 #if defined (RTX_CODE)
-
+void aarch64_gen_unlikely_cbranch (enum rtx_code, machine_mode cc_mode,
+                                  rtx label_ref);
 bool aarch64_legitimate_address_p (machine_mode, rtx, bool,
                                   aarch64_addr_query_type = ADDR_QUERY_M);
 machine_mode aarch64_select_cc_mode (RTX_CODE, rtx, rtx);
index 046195c8262fadf9aac3738426e7816d8b7a7827..fa01475aa9ee579b6a3b2526295b622157120660 100644 (file)
@@ -6414,6 +6414,13 @@ aarch64_select_cc_mode (RTX_CODE code, rtx x, rtx y)
       && GET_CODE (y) == ZERO_EXTEND)
     return CC_Cmode;
 
+  /* A test for signed overflow.  */
+  if ((GET_MODE (x) == DImode || GET_MODE (x) == TImode)
+      && code == NE
+      && GET_CODE (x) == PLUS
+      && GET_CODE (y) == SIGN_EXTEND)
+    return CC_Vmode;
+
   /* For everything else, return CCmode.  */
   return CCmode;
 }
@@ -6520,6 +6527,15 @@ aarch64_get_condition_code_1 (machine_mode mode, enum rtx_code comp_code)
        }
       break;
 
+    case E_CC_Vmode:
+      switch (comp_code)
+       {
+       case NE: return AARCH64_VS;
+       case EQ: return AARCH64_VC;
+       default: return -1;
+       }
+      break;
+
     default:
       return -1;
     }
@@ -16274,6 +16290,131 @@ aarch64_split_dimode_const_store (rtx dst, rtx src)
   return true;
 }
 
+/* Generate RTL for a conditional branch with rtx comparison CODE in
+   mode CC_MODE.  The destination of the unlikely conditional branch
+   is LABEL_REF.  */
+
+void
+aarch64_gen_unlikely_cbranch (enum rtx_code code, machine_mode cc_mode,
+                             rtx label_ref)
+{
+  rtx x;
+  x = gen_rtx_fmt_ee (code, VOIDmode,
+                     gen_rtx_REG (cc_mode, CC_REGNUM),
+                     const0_rtx);
+
+  x = gen_rtx_IF_THEN_ELSE (VOIDmode, x,
+                           gen_rtx_LABEL_REF (VOIDmode, label_ref),
+                           pc_rtx);
+  aarch64_emit_unlikely_jump (gen_rtx_SET (pc_rtx, x));
+}
+
+/* Generate DImode scratch registers for 128-bit (TImode) addition.
+
+   OP1 represents the TImode destination operand 1
+   OP2 represents the TImode destination operand 2
+   LOW_DEST represents the low half (DImode) of TImode operand 0
+   LOW_IN1 represents the low half (DImode) of TImode operand 1
+   LOW_IN2 represents the low half (DImode) of TImode operand 2
+   HIGH_DEST represents the high half (DImode) of TImode operand 0
+   HIGH_IN1 represents the high half (DImode) of TImode operand 1
+   HIGH_IN2 represents the high half (DImode) of TImode operand 2.  */
+
+void
+aarch64_addti_scratch_regs (rtx op1, rtx op2, rtx *low_dest,
+                           rtx *low_in1, rtx *low_in2,
+                           rtx *high_dest, rtx *high_in1,
+                           rtx *high_in2)
+{
+  *low_dest = gen_reg_rtx (DImode);
+  *low_in1 = gen_lowpart (DImode, op1);
+  *low_in2 = simplify_gen_subreg (DImode, op2, TImode,
+                                 subreg_lowpart_offset (DImode, TImode));
+  *high_dest = gen_reg_rtx (DImode);
+  *high_in1 = gen_highpart (DImode, op1);
+  *high_in2 = simplify_gen_subreg (DImode, op2, TImode,
+                                  subreg_highpart_offset (DImode, TImode));
+}
+
+/* Generate DImode scratch registers for 128-bit (TImode) subtraction.
+
+   This function differs from 'arch64_addti_scratch_regs' in that
+   OP1 can be an immediate constant (zero). We must call
+   subreg_highpart_offset with DImode and TImode arguments, otherwise
+   VOIDmode will be used for the const_int which generates an internal
+   error from subreg_size_highpart_offset which does not expect a size of zero.
+
+   OP1 represents the TImode destination operand 1
+   OP2 represents the TImode destination operand 2
+   LOW_DEST represents the low half (DImode) of TImode operand 0
+   LOW_IN1 represents the low half (DImode) of TImode operand 1
+   LOW_IN2 represents the low half (DImode) of TImode operand 2
+   HIGH_DEST represents the high half (DImode) of TImode operand 0
+   HIGH_IN1 represents the high half (DImode) of TImode operand 1
+   HIGH_IN2 represents the high half (DImode) of TImode operand 2.  */
+
+
+void
+aarch64_subvti_scratch_regs (rtx op1, rtx op2, rtx *low_dest,
+                            rtx *low_in1, rtx *low_in2,
+                            rtx *high_dest, rtx *high_in1,
+                            rtx *high_in2)
+{
+  *low_dest = gen_reg_rtx (DImode);
+  *low_in1 = simplify_gen_subreg (DImode, op1, TImode,
+                                 subreg_lowpart_offset (DImode, TImode));
+
+  *low_in2 = simplify_gen_subreg (DImode, op2, TImode,
+                                 subreg_lowpart_offset (DImode, TImode));
+  *high_dest = gen_reg_rtx (DImode);
+
+  *high_in1 = simplify_gen_subreg (DImode, op1, TImode,
+                                  subreg_highpart_offset (DImode, TImode));
+  *high_in2 = simplify_gen_subreg (DImode, op2, TImode,
+                                  subreg_highpart_offset (DImode, TImode));
+}
+
+/* Generate RTL for 128-bit (TImode) subtraction with overflow.
+
+   OP0 represents the TImode destination operand 0
+   LOW_DEST represents the low half (DImode) of TImode operand 0
+   LOW_IN1 represents the low half (DImode) of TImode operand 1
+   LOW_IN2 represents the low half (DImode) of TImode operand 2
+   HIGH_DEST represents the high half (DImode) of TImode operand 0
+   HIGH_IN1 represents the high half (DImode) of TImode operand 1
+   HIGH_IN2 represents the high half (DImode) of TImode operand 2.  */
+
+void
+aarch64_expand_subvti (rtx op0, rtx low_dest, rtx low_in1,
+                      rtx low_in2, rtx high_dest, rtx high_in1,
+                      rtx high_in2)
+{
+  if (low_in2 == const0_rtx)
+    {
+      low_dest = low_in1;
+      emit_insn (gen_subdi3_compare1 (high_dest, high_in1,
+                                     force_reg (DImode, high_in2)));
+    }
+  else
+    {
+      if (CONST_INT_P (low_in2))
+       {
+         low_in2 = force_reg (DImode, GEN_INT (-UINTVAL (low_in2)));
+         high_in2 = force_reg (DImode, high_in2);
+         emit_insn (gen_adddi3_compareC (low_dest, low_in1, low_in2));
+       }
+      else
+       emit_insn (gen_subdi3_compare1 (low_dest, low_in1, low_in2));
+      emit_insn (gen_subdi3_carryinCV (high_dest,
+                                      force_reg (DImode, high_in1),
+                                      high_in2));
+    }
+
+  emit_move_insn (gen_lowpart (DImode, op0), low_dest);
+  emit_move_insn (gen_highpart (DImode, op0), high_dest);
+
+}
+
 /* Implement the TARGET_ASAN_SHADOW_OFFSET hook.  */
 
 static unsigned HOST_WIDE_INT
index a014a012cc1b800c34552f08765eaefc2f973795..e9c16f9697b766a5c56b6269a83b7276654c5668 100644 (file)
   }
 )
 
+(define_expand "addv<mode>4"
+  [(match_operand:GPI 0 "register_operand")
+   (match_operand:GPI 1 "register_operand")
+   (match_operand:GPI 2 "register_operand")
+   (label_ref (match_operand 3 "" ""))]
+  ""
+{
+  emit_insn (gen_add<mode>3_compareV (operands[0], operands[1], operands[2]));
+  aarch64_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]);
+
+  DONE;
+})
+
+(define_expand "uaddv<mode>4"
+  [(match_operand:GPI 0 "register_operand")
+   (match_operand:GPI 1 "register_operand")
+   (match_operand:GPI 2 "register_operand")
+   (label_ref (match_operand 3 "" ""))]
+  ""
+{
+  emit_insn (gen_add<mode>3_compareC (operands[0], operands[1], operands[2]));
+  aarch64_gen_unlikely_cbranch (NE, CC_Cmode, operands[3]);
+
+  DONE;
+})
+
 (define_expand "addti3"
   [(set (match_operand:TI 0 "register_operand" "")
        (plus:TI (match_operand:TI 1 "register_operand" "")
-                (match_operand:TI 2 "register_operand" "")))]
+                (match_operand:TI 2 "aarch64_reg_or_imm" "")))]
   ""
 {
-  rtx low = gen_reg_rtx (DImode);
-  emit_insn (gen_adddi3_compareC (low, gen_lowpart (DImode, operands[1]),
-                                 gen_lowpart (DImode, operands[2])));
+  rtx low_dest, op1_low, op2_low, high_dest, op1_high, op2_high;
 
-  rtx high = gen_reg_rtx (DImode);
-  emit_insn (gen_adddi3_carryin (high, gen_highpart (DImode, operands[1]),
-                                gen_highpart (DImode, operands[2])));
+  aarch64_addti_scratch_regs (operands[1], operands[2],
+                             &low_dest, &op1_low, &op2_low,
+                             &high_dest, &op1_high, &op2_high);
 
-  emit_move_insn (gen_lowpart (DImode, operands[0]), low);
-  emit_move_insn (gen_highpart (DImode, operands[0]), high);
+  if (op2_low == const0_rtx)
+    {
+      low_dest = op1_low;
+      if (!aarch64_pluslong_operand (op2_high, DImode))
+       op2_high = force_reg (DImode, op2_high);
+      emit_insn (gen_adddi3 (high_dest, op1_high, op2_high));
+    }
+  else
+    {
+      emit_insn (gen_adddi3_compareC (low_dest, op1_low,
+                                     force_reg (DImode, op2_low)));
+      emit_insn (gen_adddi3_carryin (high_dest, op1_high,
+                                    force_reg (DImode, op2_high)));
+    }
+
+  emit_move_insn (gen_lowpart (DImode, operands[0]), low_dest);
+  emit_move_insn (gen_highpart (DImode, operands[0]), high_dest);
+
+  DONE;
+})
+
+(define_expand "addvti4"
+  [(match_operand:TI 0 "register_operand" "")
+   (match_operand:TI 1 "register_operand" "")
+   (match_operand:TI 2 "aarch64_reg_or_imm" "")
+   (label_ref (match_operand 3 "" ""))]
+  ""
+{
+  rtx low_dest, op1_low, op2_low, high_dest, op1_high, op2_high;
+
+  aarch64_addti_scratch_regs (operands[1], operands[2],
+                             &low_dest, &op1_low, &op2_low,
+                             &high_dest, &op1_high, &op2_high);
+
+  if (op2_low == const0_rtx)
+    {
+      low_dest = op1_low;
+      emit_insn (gen_adddi3_compareV (high_dest, op1_high,
+                                     force_reg (DImode, op2_high)));
+    }
+  else
+    {
+      emit_insn (gen_adddi3_compareC (low_dest, op1_low,
+                                     force_reg (DImode, op2_low)));
+      emit_insn (gen_adddi3_carryinV (high_dest, op1_high,
+                                     force_reg (DImode, op2_high)));
+    }
+
+  emit_move_insn (gen_lowpart (DImode, operands[0]), low_dest);
+  emit_move_insn (gen_highpart (DImode, operands[0]), high_dest);
+
+  aarch64_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]);
   DONE;
 })
 
+(define_expand "uaddvti4"
+  [(match_operand:TI 0 "register_operand" "")
+   (match_operand:TI 1 "register_operand" "")
+   (match_operand:TI 2 "aarch64_reg_or_imm" "")
+   (label_ref (match_operand 3 "" ""))]
+  ""
+{
+  rtx low_dest, op1_low, op2_low, high_dest, op1_high, op2_high;
+
+  aarch64_addti_scratch_regs (operands[1], operands[2],
+                             &low_dest, &op1_low, &op2_low,
+                             &high_dest, &op1_high, &op2_high);
+
+  if (op2_low == const0_rtx)
+    {
+      low_dest = op1_low;
+      emit_insn (gen_adddi3_compareC (high_dest, op1_high,
+                                     force_reg (DImode, op2_high)));
+    }
+  else
+    {
+      emit_insn (gen_adddi3_compareC (low_dest, op1_low,
+                                     force_reg (DImode, op2_low)));
+      emit_insn (gen_adddi3_carryinC (high_dest, op1_high,
+                                     force_reg (DImode, op2_high)));
+    }
+
+  emit_move_insn (gen_lowpart (DImode, operands[0]), low_dest);
+  emit_move_insn (gen_highpart (DImode, operands[0]), high_dest);
+
+  aarch64_gen_unlikely_cbranch (NE, CC_Cmode, operands[3]);
+  DONE;
+ })
+
 (define_insn "add<mode>3_compare0"
   [(set (reg:CC_NZ CC_REGNUM)
        (compare:CC_NZ
 
 (define_insn "add<mode>3_compareC"
   [(set (reg:CC_C CC_REGNUM)
-       (ne:CC_C
+       (compare:CC_C
          (plus:<DWI>
            (zero_extend:<DWI> (match_operand:GPI 1 "register_operand" "r"))
            (zero_extend:<DWI> (match_operand:GPI 2 "register_operand" "r")))
   [(set_attr "type" "alus_sreg")]
 )
 
+(define_insn "*add<mode>3_compareV_cconly_imm"
+  [(set (reg:CC_V CC_REGNUM)
+       (compare:CC_V
+         (plus:<DWI>
+           (sign_extend:<DWI> (match_operand:GPI 0 "register_operand" "r,r"))
+           (match_operand:<DWI> 1 "const_scalar_int_operand" ""))
+         (sign_extend:<DWI>
+          (plus:GPI
+           (match_dup 0)
+           (match_operand:GPI 2 "aarch64_plus_immediate" "I,J")))))]
+  "INTVAL (operands[1]) == INTVAL (operands[2])"
+  "@
+  cmn\\t%<w>0, %<w>1
+  cmp\\t%<w>0, #%n1"
+  [(set_attr "type" "alus_imm")]
+)
+
+(define_insn "*add<mode>3_compareV_cconly"
+  [(set (reg:CC_V CC_REGNUM)
+       (compare:CC_V
+         (plus:<DWI>
+           (sign_extend:<DWI> (match_operand:GPI 0 "register_operand" "r"))
+           (sign_extend:<DWI> (match_operand:GPI 1 "register_operand" "r")))
+         (sign_extend:<DWI> (plus:GPI (match_dup 0) (match_dup 1)))))]
+  ""
+  "cmn\\t%<w>0, %<w>1"
+  [(set_attr "type" "alus_sreg")]
+)
+
+(define_insn "*add<mode>3_compareV_imm"
+  [(set (reg:CC_V CC_REGNUM)
+       (compare:CC_V
+         (plus:<DWI>
+           (sign_extend:<DWI>
+             (match_operand:GPI 1 "register_operand" "r,r"))
+           (match_operand:GPI 2 "aarch64_plus_immediate" "I,J"))
+         (sign_extend:<DWI>
+           (plus:GPI (match_dup 1) (match_dup 2)))))
+   (set (match_operand:GPI 0 "register_operand" "=r,r")
+       (plus:GPI (match_dup 1) (match_dup 2)))]
+   ""
+   "@
+   adds\\t%<w>0, %<w>1, %<w>2
+   subs\\t%<w>0, %<w>1, #%n2"
+  [(set_attr "type" "alus_imm,alus_imm")]
+)
+
+(define_insn "add<mode>3_compareV"
+  [(set (reg:CC_V CC_REGNUM)
+       (compare:CC_V
+         (plus:<DWI>
+           (sign_extend:<DWI> (match_operand:GPI 1 "register_operand" "r"))
+           (sign_extend:<DWI> (match_operand:GPI 2 "register_operand" "r")))
+         (sign_extend:<DWI> (plus:GPI (match_dup 1) (match_dup 2)))))
+   (set (match_operand:GPI 0 "register_operand" "=r")
+       (plus:GPI (match_dup 1) (match_dup 2)))]
+  ""
+  "adds\\t%<w>0, %<w>1, %<w>2"
+  [(set_attr "type" "alus_sreg")]
+)
+
 (define_insn "*adds_shift_imm_<mode>"
   [(set (reg:CC_NZ CC_REGNUM)
        (compare:CC_NZ
-        (plus:GPI (ASHIFT:GPI 
+        (plus:GPI (ASHIFT:GPI
                    (match_operand:GPI 1 "register_operand" "r")
                    (match_operand:QI 2 "aarch64_shift_imm_<mode>" "n"))
                   (match_operand:GPI 3 "register_operand" "r"))
   [(set_attr "type" "adc_reg")]
 )
 
+(define_expand "add<mode>3_carryinC"
+  [(parallel
+     [(set (match_dup 3)
+          (compare:CC_C
+            (plus:<DWI>
+              (plus:<DWI>
+                (match_dup 4)
+                (zero_extend:<DWI>
+                  (match_operand:GPI 1 "register_operand" "")))
+              (zero_extend:<DWI>
+                (match_operand:GPI 2 "register_operand" "")))
+          (zero_extend:<DWI>
+            (plus:GPI
+              (plus:GPI (match_dup 5) (match_dup 1))
+              (match_dup 2)))))
+      (set (match_operand:GPI 0 "register_operand")
+          (plus:GPI
+            (plus:GPI (match_dup 5) (match_dup 1))
+            (match_dup 2)))])]
+   ""
+{
+  operands[3] = gen_rtx_REG (CC_Cmode, CC_REGNUM);
+  operands[4] = gen_rtx_NE (<DWI>mode, operands[3], const0_rtx);
+  operands[5] = gen_rtx_NE (<MODE>mode, operands[3], const0_rtx);
+})
+
+(define_insn "*add<mode>3_carryinC_zero"
+  [(set (reg:CC_C CC_REGNUM)
+       (compare:CC_C
+         (plus:<DWI>
+           (match_operand:<DWI> 2 "aarch64_carry_operation" "")
+           (zero_extend:<DWI> (match_operand:GPI 1 "register_operand" "r")))
+         (zero_extend:<DWI>
+           (plus:GPI
+             (match_operand:GPI 3 "aarch64_carry_operation" "")
+             (match_dup 1)))))
+   (set (match_operand:GPI 0 "register_operand")
+       (plus:GPI (match_dup 3) (match_dup 1)))]
+   ""
+   "adcs\\t%<w>0, %<w>1, <w>zr"
+  [(set_attr "type" "adc_reg")]
+)
+
+(define_insn "*add<mode>3_carryinC"
+  [(set (reg:CC_C CC_REGNUM)
+       (compare:CC_C
+         (plus:<DWI>
+           (plus:<DWI>
+             (match_operand:<DWI> 3 "aarch64_carry_operation" "")
+             (zero_extend:<DWI> (match_operand:GPI 1 "register_operand" "r")))
+           (zero_extend:<DWI> (match_operand:GPI 2 "register_operand" "r")))
+         (zero_extend:<DWI>
+           (plus:GPI
+             (plus:GPI
+               (match_operand:GPI 4 "aarch64_carry_operation" "")
+               (match_dup 1))
+             (match_dup 2)))))
+   (set (match_operand:GPI 0 "register_operand")
+       (plus:GPI
+         (plus:GPI (match_dup 4) (match_dup 1))
+         (match_dup 2)))]
+   ""
+   "adcs\\t%<w>0, %<w>1, %<w>2"
+  [(set_attr "type" "adc_reg")]
+)
+
+(define_expand "add<mode>3_carryinV"
+  [(parallel
+     [(set (reg:CC_V CC_REGNUM)
+          (compare:CC_V
+            (plus:<DWI>
+              (plus:<DWI>
+                (match_dup 3)
+                (sign_extend:<DWI>
+                  (match_operand:GPI 1 "register_operand" "")))
+              (sign_extend:<DWI>
+                (match_operand:GPI 2 "register_operand" "")))
+          (sign_extend:<DWI>
+            (plus:GPI
+              (plus:GPI (match_dup 4) (match_dup 1))
+              (match_dup 2)))))
+      (set (match_operand:GPI 0 "register_operand")
+          (plus:GPI
+            (plus:GPI (match_dup 4) (match_dup 1))
+            (match_dup 2)))])]
+   ""
+{
+  rtx cc = gen_rtx_REG (CC_Cmode, CC_REGNUM);
+  operands[3] = gen_rtx_NE (<DWI>mode, cc, const0_rtx);
+  operands[4] = gen_rtx_NE (<MODE>mode, cc, const0_rtx);
+})
+
+(define_insn "*add<mode>3_carryinV_zero"
+  [(set (reg:CC_V CC_REGNUM)
+       (compare:CC_V
+         (plus:<DWI>
+           (match_operand:<DWI> 2 "aarch64_carry_operation" "")
+           (sign_extend:<DWI> (match_operand:GPI 1 "register_operand" "r")))
+         (sign_extend:<DWI>
+           (plus:GPI
+             (match_operand:GPI 3 "aarch64_carry_operation" "")
+             (match_dup 1)))))
+   (set (match_operand:GPI 0 "register_operand")
+       (plus:GPI (match_dup 3) (match_dup 1)))]
+   ""
+   "adcs\\t%<w>0, %<w>1, <w>zr"
+  [(set_attr "type" "adc_reg")]
+)
+
+(define_insn "*add<mode>3_carryinV"
+  [(set (reg:CC_V CC_REGNUM)
+       (compare:CC_V
+         (plus:<DWI>
+           (plus:<DWI>
+             (match_operand:<DWI> 3 "aarch64_carry_operation" "")
+             (sign_extend:<DWI> (match_operand:GPI 1 "register_operand" "r")))
+           (sign_extend:<DWI> (match_operand:GPI 2 "register_operand" "r")))
+         (sign_extend:<DWI>
+           (plus:GPI
+             (plus:GPI
+               (match_operand:GPI 4 "aarch64_carry_operation" "")
+               (match_dup 1))
+             (match_dup 2)))))
+   (set (match_operand:GPI 0 "register_operand")
+       (plus:GPI
+         (plus:GPI (match_dup 4) (match_dup 1))
+         (match_dup 2)))]
+   ""
+   "adcs\\t%<w>0, %<w>1, %<w>2"
+  [(set_attr "type" "adc_reg")]
+)
+
 (define_insn "*add_uxt<mode>_shift2"
   [(set (match_operand:GPI 0 "register_operand" "=rk")
        (plus:GPI (and:GPI
    (set_attr "simd" "*,yes")]
 )
 
+(define_expand "subv<mode>4"
+  [(match_operand:GPI 0 "register_operand")
+   (match_operand:GPI 1 "aarch64_reg_or_zero")
+   (match_operand:GPI 2 "aarch64_reg_or_zero")
+   (label_ref (match_operand 3 "" ""))]
+  ""
+{
+  emit_insn (gen_sub<mode>3_compare1 (operands[0], operands[1], operands[2]));
+  aarch64_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]);
+
+  DONE;
+})
+
+(define_expand "usubv<mode>4"
+  [(match_operand:GPI 0 "register_operand")
+   (match_operand:GPI 1 "aarch64_reg_or_zero")
+   (match_operand:GPI 2 "aarch64_reg_or_zero")
+   (label_ref (match_operand 3 "" ""))]
+  ""
+{
+  emit_insn (gen_sub<mode>3_compare1 (operands[0], operands[1], operands[2]));
+  aarch64_gen_unlikely_cbranch (LTU, CCmode, operands[3]);
+
+  DONE;
+})
+
 (define_expand "subti3"
   [(set (match_operand:TI 0 "register_operand" "")
-       (minus:TI (match_operand:TI 1 "register_operand" "")
+       (minus:TI (match_operand:TI 1 "aarch64_reg_or_zero" "")
                  (match_operand:TI 2 "register_operand" "")))]
   ""
 {
-  rtx low = gen_reg_rtx (DImode);
-  emit_insn (gen_subdi3_compare1 (low, gen_lowpart (DImode, operands[1]),
-                                 gen_lowpart (DImode, operands[2])));
+  rtx low_dest, op1_low, op2_low, high_dest, op1_high, op2_high;
 
-  rtx high = gen_reg_rtx (DImode);
-  emit_insn (gen_subdi3_carryin (high, gen_highpart (DImode, operands[1]),
-                                gen_highpart (DImode, operands[2])));
+  aarch64_subvti_scratch_regs (operands[1], operands[2],
+                              &low_dest, &op1_low, &op2_low,
+                              &high_dest, &op1_high, &op2_high);
 
-  emit_move_insn (gen_lowpart (DImode, operands[0]), low);
-  emit_move_insn (gen_highpart (DImode, operands[0]), high);
+  emit_insn (gen_subdi3_compare1 (low_dest, op1_low, op2_low));
+  emit_insn (gen_subdi3_carryin (high_dest, op1_high, op2_high));
+
+  emit_move_insn (gen_lowpart (DImode, operands[0]), low_dest);
+  emit_move_insn (gen_highpart (DImode, operands[0]), high_dest);
+  DONE;
+})
+
+(define_expand "subvti4"
+  [(match_operand:TI 0 "register_operand")
+   (match_operand:TI 1 "aarch64_reg_or_zero")
+   (match_operand:TI 2 "aarch64_reg_or_imm")
+   (label_ref (match_operand 3 "" ""))]
+  ""
+{
+  rtx low_dest, op1_low, op2_low, high_dest, op1_high, op2_high;
+
+  aarch64_subvti_scratch_regs (operands[1], operands[2],
+                              &low_dest, &op1_low, &op2_low,
+                              &high_dest, &op1_high, &op2_high);
+  aarch64_expand_subvti (operands[0], low_dest, op1_low, op2_low,
+                        high_dest, op1_high, op2_high);
+
+  aarch64_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]);
+  DONE;
+})
+
+(define_expand "usubvti4"
+  [(match_operand:TI 0 "register_operand")
+   (match_operand:TI 1 "aarch64_reg_or_zero")
+   (match_operand:TI 2 "aarch64_reg_or_imm")
+   (label_ref (match_operand 3 "" ""))]
+  ""
+{
+  rtx low_dest, op1_low, op2_low, high_dest, op1_high, op2_high;
+
+  aarch64_subvti_scratch_regs (operands[1], operands[2],
+                                   &low_dest, &op1_low, &op2_low,
+                              &high_dest, &op1_high, &op2_high);
+  aarch64_expand_subvti (operands[0], low_dest, op1_low, op2_low,
+                        high_dest, op1_high, op2_high);
+
+  aarch64_gen_unlikely_cbranch (LTU, CCmode, operands[3]);
   DONE;
 })
 
   [(set_attr "type" "alus_sreg")]
 )
 
+(define_insn "*sub<mode>3_compare1_imm"
+  [(set (reg:CC CC_REGNUM)
+       (compare:CC
+         (match_operand:GPI 1 "aarch64_reg_or_zero" "rZ,rZ")
+         (match_operand:GPI 2 "aarch64_plus_immediate" "I,J")))
+   (set (match_operand:GPI 0 "register_operand" "=r,r")
+       (plus:GPI
+         (match_dup 1)
+         (match_operand:GPI 3 "aarch64_plus_immediate" "J,I")))]
+  "UINTVAL (operands[2]) == -UINTVAL (operands[3])"
+  "@
+  subs\\t%<w>0, %<w>1, #%n3
+  adds\\t%<w>0, %<w>1, %3"
+  [(set_attr "type" "alus_imm")]
+)
+
 (define_insn "sub<mode>3_compare1"
   [(set (reg:CC CC_REGNUM)
        (compare:CC
   [(set_attr "type" "adc_reg")]
 )
 
+(define_expand "sub<mode>3_carryinCV"
+  [(parallel
+     [(set (reg:CC CC_REGNUM)
+          (compare:CC
+            (sign_extend:<DWI>
+              (match_operand:GPI 1 "aarch64_reg_or_zero" ""))
+            (plus:<DWI>
+              (sign_extend:<DWI>
+                (match_operand:GPI 2 "register_operand" ""))
+              (ltu:<DWI> (reg:CC CC_REGNUM) (const_int 0)))))
+      (set (match_operand:GPI 0 "register_operand" "")
+          (minus:GPI
+            (minus:GPI (match_dup 1) (match_dup 2))
+            (ltu:GPI (reg:CC CC_REGNUM) (const_int 0))))])]
+   ""
+)
+
+(define_insn "*sub<mode>3_carryinCV_z1_z2"
+  [(set (reg:CC CC_REGNUM)
+       (compare:CC
+         (const_int 0)
+         (match_operand:<DWI> 2 "aarch64_borrow_operation" "")))
+   (set (match_operand:GPI 0 "register_operand" "=r")
+       (neg:GPI (match_operand:GPI 1 "aarch64_borrow_operation" "")))]
+   ""
+   "sbcs\\t%<w>0, <w>zr, <w>zr"
+  [(set_attr "type" "adc_reg")]
+)
+
+(define_insn "*sub<mode>3_carryinCV_z1"
+  [(set (reg:CC CC_REGNUM)
+       (compare:CC
+         (const_int 0)
+         (plus:<DWI>
+           (sign_extend:<DWI>
+             (match_operand:GPI 1 "register_operand" "r"))
+           (match_operand:<DWI> 2 "aarch64_borrow_operation" ""))))
+   (set (match_operand:GPI 0 "register_operand" "=r")
+       (minus:GPI
+         (neg:GPI (match_dup 1))
+         (match_operand:GPI 3 "aarch64_borrow_operation" "")))]
+   ""
+   "sbcs\\t%<w>0, <w>zr, %<w>1"
+  [(set_attr "type" "adc_reg")]
+)
+
+(define_insn "*sub<mode>3_carryinCV_z2"
+  [(set (reg:CC CC_REGNUM)
+       (compare:CC
+         (sign_extend:<DWI>
+           (match_operand:GPI 1 "register_operand" "r"))
+         (match_operand:<DWI> 2 "aarch64_borrow_operation" "")))
+   (set (match_operand:GPI 0 "register_operand" "=r")
+       (minus:GPI
+         (match_dup 1)
+         (match_operand:GPI 3 "aarch64_borrow_operation" "")))]
+   ""
+   "sbcs\\t%<w>0, %<w>1, <w>zr"
+  [(set_attr "type" "adc_reg")]
+)
+
+(define_insn "*sub<mode>3_carryinCV"
+  [(set (reg:CC CC_REGNUM)
+       (compare:CC
+         (sign_extend:<DWI>
+           (match_operand:GPI 1 "register_operand" "r"))
+         (plus:<DWI>
+           (sign_extend:<DWI>
+             (match_operand:GPI 2 "register_operand" "r"))
+           (match_operand:<DWI> 3 "aarch64_borrow_operation" ""))))
+   (set (match_operand:GPI 0 "register_operand" "=r")
+       (minus:GPI
+         (minus:GPI (match_dup 1) (match_dup 2))
+         (match_operand:GPI 4 "aarch64_borrow_operation" "")))]
+   ""
+   "sbcs\\t%<w>0, %<w>1, %<w>2"
+  [(set_attr "type" "adc_reg")]
+)
+
 (define_insn "*sub_uxt<mode>_shift2"
   [(set (match_operand:GPI 0 "register_operand" "=rk")
        (minus:GPI (match_operand:GPI 4 "register_operand" "rk")
index f55ecc3454eebdff46a9f4c15e2d2da75eb6a481..b8b309f71f94bd2bbe4be9fda5c07ac33515ec01 100644 (file)
@@ -1,3 +1,19 @@
+2018-07-19  Michael Collison  <michael.collison@arm.com>
+           Richard Henderson <rth@redhat.com>
+
+       * gcc.target/aarch64/builtin_sadd_128.c: New testcase.
+       * gcc.target/aarch64/builtin_saddl.c: New testcase.
+       * gcc.target/aarch64/builtin_saddll.c: New testcase.
+       * gcc.target/aarch64/builtin_uadd_128.c: New testcase.
+       * gcc.target/aarch64/builtin_uaddl.c: New testcase.
+       * gcc.target/aarch64/builtin_uaddll.c: New testcase.
+       * gcc.target/aarch64/builtin_ssub_128.c: New testcase.
+       * gcc.target/aarch64/builtin_ssubl.c: New testcase.
+       * gcc.target/aarch64/builtin_ssubll.c: New testcase.
+       * gcc.target/aarch64/builtin_usub_128.c: New testcase.
+       * gcc.target/aarch64/builtin_usubl.c: New testcase.
+       * gcc.target/aarch64/builtin_usubll.c: New testcase.
+
 2018-07-19  Paolo Carlini  <paolo.carlini@oracle.com>
 
        Revert fix for c++/59480 (and testsuite followup)
diff --git a/gcc/testsuite/gcc.target/aarch64/builtin_sadd_128.c b/gcc/testsuite/gcc.target/aarch64/builtin_sadd_128.c
new file mode 100644 (file)
index 0000000..0b31500
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" }  */
+
+extern void overflow_handler ();
+
+__int128 overflow_add (__int128 x, __int128 y)
+{
+  __int128 r;
+
+  int ovr = __builtin_add_overflow (x, y, &r);
+  if (ovr)
+    overflow_handler ();
+
+  return r;
+}
+
+/* { dg-final { scan-assembler "adds" } } */
+/* { dg-final { scan-assembler "adcs" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/builtin_saddl.c b/gcc/testsuite/gcc.target/aarch64/builtin_saddl.c
new file mode 100644 (file)
index 0000000..9768a98
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" }  */
+
+extern void overflow_handler ();
+
+long overflow_add (long x, long y)
+{
+  long r;
+
+  int ovr = __builtin_saddl_overflow (x, y, &r);
+  if (ovr)
+    overflow_handler ();
+
+  return r;
+}
+
+/* { dg-final { scan-assembler "adds" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/builtin_saddll.c b/gcc/testsuite/gcc.target/aarch64/builtin_saddll.c
new file mode 100644 (file)
index 0000000..126a526
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" }  */
+
+extern void overflow_handler ();
+
+long long overflow_add (long long x, long long y)
+{
+  long long r;
+
+  int ovr = __builtin_saddll_overflow (x, y, &r);
+  if (ovr)
+    overflow_handler ();
+
+  return r;
+}
+
+/* { dg-final { scan-assembler "adds" } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/builtin_ssub_128.c b/gcc/testsuite/gcc.target/aarch64/builtin_ssub_128.c
new file mode 100644 (file)
index 0000000..c1261e3
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" }  */
+
+extern void overflow_handler ();
+
+__int128 overflow_sub (__int128 x, __int128 y)
+{
+  __int128 r;
+
+  int ovr = __builtin_sub_overflow (x, y, &r);
+  if (ovr)
+    overflow_handler ();
+
+  return r;
+}
+
+/* { dg-final { scan-assembler "subs" } } */
+/* { dg-final { scan-assembler "sbcs" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/builtin_ssubl.c b/gcc/testsuite/gcc.target/aarch64/builtin_ssubl.c
new file mode 100644 (file)
index 0000000..1040464
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" }  */
+
+extern void overflow_handler ();
+
+long overflow_sub (long x, long y)
+{
+  long r;
+
+  int ovr = __builtin_ssubl_overflow (x, y, &r);
+  if (ovr)
+    overflow_handler ();
+
+  return r;
+}
+
+/* { dg-final { scan-assembler "subs" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/builtin_ssubll.c b/gcc/testsuite/gcc.target/aarch64/builtin_ssubll.c
new file mode 100644 (file)
index 0000000..a03df88
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" }  */
+
+extern void overflow_handler ();
+
+long long overflow_sub (long long x, long long y)
+{
+  long long r;
+
+  int ovr = __builtin_ssubll_overflow (x, y, &r);
+  if (ovr)
+    overflow_handler ();
+
+  return r;
+}
+
+/* { dg-final { scan-assembler "subs" } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/builtin_uadd_128.c b/gcc/testsuite/gcc.target/aarch64/builtin_uadd_128.c
new file mode 100644 (file)
index 0000000..c573c2a
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" }  */
+
+extern void overflow_handler ();
+
+unsigned __int128 overflow_add (unsigned __int128 x, unsigned __int128 y)
+{
+  unsigned __int128 r;
+
+  int ovr = __builtin_add_overflow (x, y, &r);
+  if (ovr)
+    overflow_handler ();
+
+  return r;
+}
+
+/* { dg-final { scan-assembler "adds" } } */
+/* { dg-final { scan-assembler "adcs" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/builtin_uaddl.c b/gcc/testsuite/gcc.target/aarch64/builtin_uaddl.c
new file mode 100644 (file)
index 0000000..e325591
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" }  */
+
+extern void overflow_handler ();
+
+unsigned long overflow_add (unsigned long x, unsigned long y)
+{
+  unsigned long r;
+
+  int ovr = __builtin_uaddl_overflow (x, y, &r);
+  if (ovr)
+    overflow_handler ();
+
+  return r;
+}
+
+/* { dg-final { scan-assembler "adds" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/builtin_uaddll.c b/gcc/testsuite/gcc.target/aarch64/builtin_uaddll.c
new file mode 100644 (file)
index 0000000..5f42886
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" }  */
+
+extern void overflow_handler ();
+
+unsigned long long overflow_add (unsigned long long x, unsigned long long y)
+{
+  unsigned long long r;
+
+  int ovr = __builtin_uaddll_overflow (x, y, &r);
+  if (ovr)
+    overflow_handler ();
+
+  return r;
+}
+
+/* { dg-final { scan-assembler "adds" } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/builtin_usub_128.c b/gcc/testsuite/gcc.target/aarch64/builtin_usub_128.c
new file mode 100644 (file)
index 0000000..a84f4a4
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" }  */
+
+extern void overflow_handler ();
+
+unsigned __int128 overflow_sub (unsigned __int128 x, unsigned __int128 y)
+{
+  unsigned __int128 r;
+
+  int ovr = __builtin_sub_overflow (x, y, &r);
+  if (ovr)
+    overflow_handler ();
+
+  return r;
+}
+
+/* { dg-final { scan-assembler "subs" } } */
+/* { dg-final { scan-assembler "sbcs" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/builtin_usubl.c b/gcc/testsuite/gcc.target/aarch64/builtin_usubl.c
new file mode 100644 (file)
index 0000000..ed033da
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" }  */
+
+extern void overflow_handler ();
+
+unsigned long overflow_sub (unsigned long x, unsigned long y)
+{
+  unsigned long r;
+
+  int ovr = __builtin_usubl_overflow (x, y, &r);
+  if (ovr)
+    overflow_handler ();
+
+  return r;
+}
+
+/* { dg-final { scan-assembler "subs" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/builtin_usubll.c b/gcc/testsuite/gcc.target/aarch64/builtin_usubll.c
new file mode 100644 (file)
index 0000000..a742f0c
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" }  */
+
+extern void overflow_handler ();
+
+unsigned long long overflow_sub (unsigned long long x, unsigned long long y)
+{
+  unsigned long long r;
+
+  int ovr = __builtin_usubll_overflow (x, y, &r);
+  if (ovr)
+    overflow_handler ();
+
+  return r;
+}
+
+/* { dg-final { scan-assembler "subs" } } */
+