[arm] Early expansion of uaddvdi4.
authorRichard Earnshaw <rearnsha@arm.com>
Fri, 18 Oct 2019 19:04:15 +0000 (19:04 +0000)
committerRichard Earnshaw <rearnsha@gcc.gnu.org>
Fri, 18 Oct 2019 19:04:15 +0000 (19:04 +0000)
This code borrows strongly on the uaddvti4 expansion for aarch64 since
the principles are similar.  Firstly, if the one of the low words of
the expansion is 0, we can simply copy the other low word to the
destination and use uaddvsi4 for the upper word.  If that doesn't work
we have to handle three possible cases for the upper work (the lower
word is simply an add-with-carry operation as for adddi3): zero in the
upper word, some other constant and a register (each has a different
canonicalization).  We use CC_ADCmode (a new CC mode variant) to
describe the cases as the introduction of the carry means we can
no-longer use the normal overflow trick of comparing the sum against
one of the operands.

* config/arm/arm-modes.def (CC_ADC): New CC mode.
* config/arm/arm.c (arm_select_cc_mode): Detect selection of
CC_ADCmode.
(maybe_get_arm_condition_code): Handle CC_ADCmode.
* config/arm/arm.md (uaddvdi4): Early expansion of unsigned addition
with overflow.
(addsi3_cin_cout_reg, addsi3_cin_cout_imm, addsi3_cin_cout_0): New
expand patterns.
(addsi3_cin_cout_reg_insn, addsi3_cin_cout_0_insn): New insn patterns
(addsi3_cin_cout_imm_insn): Likewise.
(adddi3_compareC): Delete insn.
* config/arm/predicates.md (arm_carry_operation): Handle CC_ADCmode.

From-SVN: r277183

gcc/ChangeLog
gcc/config/arm/arm-modes.def
gcc/config/arm/arm.c
gcc/config/arm/arm.md
gcc/config/arm/predicates.md

index 3b8f9f3f33da72ffef068e71a963cfb3129933d6..902cf51a37c8aa9d6d5061aa820592122aa2cc10 100644 (file)
@@ -1,3 +1,18 @@
+2019-10-18  Richard Earnshaw  <rearnsha@arm.com>
+
+       * config/arm/arm-modes.def (CC_ADC): New CC mode.
+       * config/arm/arm.c (arm_select_cc_mode): Detect selection of
+       CC_ADCmode.
+       (maybe_get_arm_condition_code): Handle CC_ADCmode.
+       * config/arm/arm.md (uaddvdi4): Early expansion of unsigned addition
+       with overflow.
+       (addsi3_cin_cout_reg, addsi3_cin_cout_imm, addsi3_cin_cout_0): New
+       expand patterns.
+       (addsi3_cin_cout_reg_insn, addsi3_cin_cout_0_insn): New insn patterns
+       (addsi3_cin_cout_imm_insn): Likewise.
+       (adddi3_compareC): Delete insn.
+       * config/arm/predicates.md (arm_carry_operation): Handle CC_ADCmode.
+
 2019-10-18  Richard Earnshaw  <rearnsha@arm.com>
 
        * config/arm/arm.md (adddi3): Call gen_addsi3_compare_op1.
index f0eb8415b937b16d8b2762be60c47a0c65b40193..a6b520df32d63c10cdba3cf4d1c2a4e339e9e160 100644 (file)
@@ -42,6 +42,9 @@ ADJUST_FLOAT_FORMAT (HF, ((arm_fp16_format == ARM_FP16_FORMAT_ALTERNATIVE)
    CC_Bmode should be used if only the C flag is correct after a subtract
      (eg after an unsigned borrow with carry-in propagation).
    (used for DImode signed comparisons).
+   CC_ADCmode is used when the carry is formed from the output of ADC for an
+     addtion.  In this case we cannot use the trick of comparing the sum
+     against one of the other operands.
    CCmode should be used otherwise.  */
 
 CC_MODE (CC_NOOV);
@@ -65,6 +68,7 @@ CC_MODE (CC_C);
 CC_MODE (CC_B);
 CC_MODE (CC_N);
 CC_MODE (CC_V);
+CC_MODE (CC_ADC);
 
 /* Vector modes.  */
 VECTOR_MODES (INT, 4);        /*            V4QI V2HI */
index 6c1e9132ca8d325ac4fd84014b9b31460902875b..fb1a68106519ae2cbefe81ad535e2a9f39545433 100644 (file)
@@ -15387,6 +15387,14 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
       && (rtx_equal_p (XEXP (x, 0), y) || rtx_equal_p (XEXP (x, 1), y)))
     return CC_Cmode;
 
+  if (GET_MODE (x) == DImode
+      && GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND
+      && CONST_INT_P (y)
+      && UINTVAL (y) == 0x800000000
+      && (op == GEU || op == LTU))
+    return CC_ADCmode;
+
   if (GET_MODE (x) == DImode
       && (op == GE || op == LT)
       && GET_CODE (x) == SIGN_EXTEND
@@ -23952,6 +23960,14 @@ maybe_get_arm_condition_code (rtx comparison)
        default: return ARM_NV;
        }
 
+    case E_CC_ADCmode:
+      switch (comp_code)
+       {
+       case GEU: return ARM_CS;
+       case LTU: return ARM_CC;
+       default: return ARM_NV;
+       }
+
     case E_CCmode:
     case E_CC_RSBmode:
       switch (comp_code)
index 4ea6f4b226c397e483c34006e56621a7ec7745c3..9f0e43571fdbb99b3bf1980ff7b082fbd8d2fe84 100644 (file)
 (define_expand "uaddvdi4"
   [(match_operand:DI 0 "s_register_operand")
    (match_operand:DI 1 "s_register_operand")
-   (match_operand:DI 2 "s_register_operand")
+   (match_operand:DI 2 "reg_or_int_operand")
    (match_operand 3 "")]
   "TARGET_32BIT"
 {
-  emit_insn (gen_adddi3_compareC (operands[0], operands[1], operands[2]));
-  arm_gen_unlikely_cbranch (LTU, CC_Cmode, operands[3]);
+  rtx lo_result, hi_result;
+  rtx lo_op1, hi_op1, lo_op2, hi_op2;
+  arm_decompose_di_binop (operands[1], operands[2], &lo_op1, &hi_op1,
+                         &lo_op2, &hi_op2);
+  lo_result = gen_lowpart (SImode, operands[0]);
+  hi_result = gen_highpart (SImode, operands[0]);
+
+  if (lo_op2 == const0_rtx)
+    {
+      emit_move_insn (lo_result, lo_op1);
+      if (!arm_add_operand (hi_op2, SImode))
+       hi_op2 = force_reg (SImode, hi_op2);
+
+      gen_uaddvsi4 (hi_result, hi_op1, hi_op2, operands[3]);
+    }
+  else
+    {
+      if (!arm_add_operand (lo_op2, SImode))
+       lo_op2 = force_reg (SImode, lo_op2);
+      if (!arm_not_operand (hi_op2, SImode))
+       hi_op2 = force_reg (SImode, hi_op2);
+
+      emit_insn (gen_addsi3_compare_op1 (lo_result, lo_op1, lo_op2));
+
+      if (hi_op2 == const0_rtx)
+        emit_insn (gen_addsi3_cin_cout_0 (hi_result, hi_op1));
+      else if (CONST_INT_P (hi_op2))
+        emit_insn (gen_addsi3_cin_cout_imm (hi_result, hi_op1, hi_op2));
+      else
+        emit_insn (gen_addsi3_cin_cout_reg (hi_result, hi_op1, hi_op2));
+
+      arm_gen_unlikely_cbranch (GEU, CC_ADCmode, operands[3]);
+    }
 
   DONE;
 })
 
+(define_expand "addsi3_cin_cout_reg"
+  [(parallel
+    [(set (match_dup 3)
+         (compare:CC_ADC
+          (plus:DI
+           (plus:DI (match_dup 4)
+                    (zero_extend:DI (match_operand:SI 1 "s_register_operand")))
+           (zero_extend:DI (match_operand:SI 2 "s_register_operand")))
+          (const_int 4294967296)))
+     (set (match_operand:SI 0 "s_register_operand")
+         (plus:SI (plus:SI (match_dup 5) (match_dup 1))
+                  (match_dup 2)))])]
+  "TARGET_32BIT"
+  {
+    operands[3] = gen_rtx_REG (CC_ADCmode, CC_REGNUM);
+    rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
+    operands[4] = gen_rtx_LTU (DImode, ccin, const0_rtx);
+    operands[5] = gen_rtx_LTU (SImode, ccin, const0_rtx);
+  }
+)
+
+(define_insn "*addsi3_cin_cout_reg_insn"
+  [(set (reg:CC_ADC CC_REGNUM)
+       (compare:CC_ADC
+        (plus:DI
+         (plus:DI
+          (match_operand:DI 3 "arm_carry_operation" "")
+          (zero_extend:DI (match_operand:SI 1 "s_register_operand" "%0,r")))
+         (zero_extend:DI (match_operand:SI 2 "s_register_operand" "l,r")))
+       (const_int 4294967296)))
+   (set (match_operand:SI 0 "s_register_operand" "=l,r")
+       (plus:SI (plus:SI (match_operand:SI 4 "arm_carry_operation" "")
+                         (match_dup 1))
+                (match_dup 2)))]
+  "TARGET_32BIT"
+  "@
+   adcs%?\\t%0, %0, %2
+   adcs%?\\t%0, %1, %2"
+  [(set_attr "type" "alus_sreg")
+   (set_attr "arch" "t2,*")
+   (set_attr "length" "2,4")]
+)
+
+(define_expand "addsi3_cin_cout_imm"
+  [(parallel
+    [(set (match_dup 3)
+         (compare:CC_ADC
+          (plus:DI
+           (plus:DI (match_dup 4)
+                    (zero_extend:DI (match_operand:SI 1 "s_register_operand")))
+           (match_dup 6))
+          (const_int 4294967296)))
+     (set (match_operand:SI 0 "s_register_operand")
+         (plus:SI (plus:SI (match_dup 5) (match_dup 1))
+                  (match_operand:SI 2 "arm_adcimm_operand")))])]
+  "TARGET_32BIT"
+  {
+    operands[3] = gen_rtx_REG (CC_ADCmode, CC_REGNUM);
+    rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
+    operands[4] = gen_rtx_LTU (DImode, ccin, const0_rtx);
+    operands[5] = gen_rtx_LTU (SImode, ccin, const0_rtx);
+    operands[6] = GEN_INT (UINTVAL (operands[2]) & 0xffffffff);
+  }
+)
+
+(define_insn "*addsi3_cin_cout_imm_insn"
+  [(set (reg:CC_ADC CC_REGNUM)
+       (compare:CC_ADC
+        (plus:DI
+         (plus:DI
+          (match_operand:DI 3 "arm_carry_operation" "")
+          (zero_extend:DI (match_operand:SI 1 "s_register_operand" "r,r")))
+         (match_operand:DI 5 "const_int_operand" "n,n"))
+       (const_int 4294967296)))
+   (set (match_operand:SI 0 "s_register_operand" "=r,r")
+       (plus:SI (plus:SI (match_operand:SI 4 "arm_carry_operation" "")
+                         (match_dup 1))
+                (match_operand:SI 2 "arm_adcimm_operand" "I,K")))]
+  "TARGET_32BIT
+   && (UINTVAL (operands[2]) & 0xffffffff) == UINTVAL (operands[5])"
+  "@
+   adcs%?\\t%0, %1, %2
+   sbcs%?\\t%0, %1, #%B2"
+  [(set_attr "type" "alus_imm")]
+)
+
+(define_expand "addsi3_cin_cout_0"
+  [(parallel
+    [(set (match_dup 2)
+         (compare:CC_ADC
+          (plus:DI (match_dup 3)
+                   (zero_extend:DI (match_operand:SI 1 "s_register_operand")))
+          (const_int 4294967296)))
+     (set (match_operand:SI 0 "s_register_operand")
+         (plus:SI (match_dup 4) (match_dup 1)))])]
+  "TARGET_32BIT"
+  {
+    operands[2] = gen_rtx_REG (CC_ADCmode, CC_REGNUM);
+    rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
+    operands[3] = gen_rtx_LTU (DImode, ccin, const0_rtx);
+    operands[4] = gen_rtx_LTU (SImode, ccin, const0_rtx);
+  }
+)
+
+(define_insn "*addsi3_cin_cout_0_insn"
+  [(set (reg:CC_ADC CC_REGNUM)
+       (compare:CC_ADC
+        (plus:DI
+         (match_operand:DI 2 "arm_carry_operation" "")
+         (zero_extend:DI (match_operand:SI 1 "s_register_operand" "r")))
+       (const_int 4294967296)))
+   (set (match_operand:SI 0 "s_register_operand" "=r")
+       (plus:SI (match_operand:SI 3 "arm_carry_operation" "") (match_dup 1)))]
+  "TARGET_32BIT"
+  "adcs%?\\t%0, %1, #0"
+  [(set_attr "type" "alus_imm")]
+)
+
 (define_expand "addsi3"
   [(set (match_operand:SI          0 "s_register_operand")
        (plus:SI (match_operand:SI 1 "s_register_operand")
    (set_attr "type" "alus_sreg")]
 )
 
-(define_insn "adddi3_compareC"
-  [(set (reg:CC_C CC_REGNUM)
-       (compare:CC_C
-         (plus:DI
-           (match_operand:DI 1 "register_operand" "r")
-           (match_operand:DI 2 "register_operand" "r"))
-         (match_dup 1)))
-   (set (match_operand:DI 0 "register_operand" "=&r")
-       (plus:DI (match_dup 1) (match_dup 2)))]
-  "TARGET_32BIT"
-  "adds\\t%Q0, %Q1, %Q2;adcs\\t%R0, %R1, %R2"
- [(set_attr "conds" "set")
-   (set_attr "length" "8")
-   (set_attr "type" "multiple")]
-)
-
 (define_insn "addsi3_compare0"
   [(set (reg:CC_NOOV CC_REGNUM)
        (compare:CC_NOOV
index d9470df80933b50490c40d2beeddb67eefdae695..8a8f10ccb501d1c9e2ac7f18f4de138fd7634fe7 100644 (file)
     machine_mode ccmode = GET_MODE (op0);
     if (ccmode == CC_Cmode)
       return GET_CODE (op) == LTU;
-    else if (ccmode == CCmode || ccmode == CC_RSBmode)
+    else if (ccmode == CCmode || ccmode == CC_RSBmode || ccmode == CC_ADCmode)
       return GET_CODE (op) == GEU;
 
     return false;