[arm] Improve constant handling for subvsi4.
authorRichard Earnshaw <rearnsha@arm.com>
Fri, 18 Oct 2019 19:05:01 +0000 (19:05 +0000)
committerRichard Earnshaw <rearnsha@gcc.gnu.org>
Fri, 18 Oct 2019 19:05:01 +0000 (19:05 +0000)
This patch addresses constant handling in subvsi4.  Either operand may
be a constant.  If the second input (operand[2]) is a constant, then
we can canonicalize this into an addition form, providing we take care
of the INT_MIN case.  In that case the negation has to handle the fact
that -INT_MIN is still INT_MIN and we need to ensure that a subtract
operation is performed rather than an addition.  The remaining cases
are largely duals of the usubvsi4 expansion.

This patch also fixes a technical correctness bug in the old
expansion, where we did not realy describe the test for overflow in
the RTL.  We seem to have got away with that, however...

* config/arm/arm.md (subv<mode>4): Delete.
(subvdi4): New expander pattern.
(subvsi4): Likewise.  Handle some immediate values.
(subvsi3_intmin): New insn pattern.
(subvsi3): Likewise.
(subvsi3_imm1): Likewise.
* config/arm/arm.c (select_cc_mode): Also allow minus for CC_V
idioms.

From-SVN: r277189

gcc/ChangeLog
gcc/config/arm/arm.c
gcc/config/arm/arm.md

index dbc421de968674cbc1aea5c192b13b8581eabac0..153792e3ecd1eb2728bd3a5ab83f4ca21cacc29d 100644 (file)
@@ -1,3 +1,14 @@
+2019-10-18  Richard Earnshaw  <rearnsha@arm.com>
+
+       * config/arm/arm.md (subv<mode>4): Delete.
+       (subvdi4): New expander pattern.
+       (subvsi4): Likewise.  Handle some immediate values.
+       (subvsi3_intmin): New insn pattern.
+       (subvsi3): Likewise.
+       (subvsi3_imm1): Likewise.
+       * config/arm/arm.c (select_cc_mode): Also allow minus for CC_V
+       idioms.
+
 2019-10-18  Richard Earnshaw  <rearnsha@arm.com>
 
        * config/arm/arm.md (usubvdi4): Allow registers or integers for
index fe240b2c1b8e7bee2a0a9d932e8a03590578bd70..5491ad0fb43e322c073d6d6dfeed5970fa9cfa73 100644 (file)
@@ -15413,11 +15413,12 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
 
   if (GET_MODE (x) == DImode
       && (op == EQ || op == NE)
-      && GET_CODE (x) == PLUS
+      && (GET_CODE (x) == PLUS
+         || GET_CODE (x) == MINUS)
       && (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
          || GET_CODE (XEXP (x, 1)) == SIGN_EXTEND)
       && GET_CODE (y) == SIGN_EXTEND
-      && GET_CODE (XEXP (y, 0)) == PLUS)
+      && GET_CODE (XEXP (y, 0)) == GET_CODE (x))
     return CC_Vmode;
 
   if (GET_MODE_CLASS (GET_MODE (x)) == MODE_CC)
index 92f1823cdfac07b91f9001b920040e6a1221d5da..05b735cfccdeec2019cd625f2b66d7c297702521 100644 (file)
    (set_attr "type" "alus_sreg")]
 )
 
+(define_insn "subvsi3_intmin"
+  [(set (reg:CC_V CC_REGNUM)
+       (compare:CC_V
+         (plus:DI
+           (sign_extend:DI
+            (match_operand:SI 1 "register_operand" "r"))
+           (const_int 2147483648))
+         (sign_extend:DI (plus:SI (match_dup 1) (const_int -2147483648)))))
+   (set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (match_dup 1) (const_int -2147483648)))]
+  "TARGET_32BIT"
+  "subs%?\\t%0, %1, #-2147483648"
+  [(set_attr "conds" "set")
+   (set_attr "type" "alus_imm")]
+)
+
 (define_insn "addsi3_compareV_imm"
   [(set (reg:CC_V CC_REGNUM)
        (compare:CC_V
     (set_attr "type" "adcs_reg")]
 )
 
-(define_expand "subv<mode>4"
-  [(match_operand:SIDI 0 "register_operand")
-   (match_operand:SIDI 1 "register_operand")
-   (match_operand:SIDI 2 "register_operand")
+(define_expand "subvsi4"
+  [(match_operand:SI 0 "s_register_operand")
+   (match_operand:SI 1 "arm_rhs_operand")
+   (match_operand:SI 2 "arm_add_operand")
+   (match_operand 3 "")]
+  "TARGET_32BIT"
+{
+  if (CONST_INT_P (operands[1]) && CONST_INT_P (operands[2]))
+    {
+      /* If both operands are constants we can decide the result statically.  */
+      wi::overflow_type overflow;
+      wide_int val = wi::sub (rtx_mode_t (operands[1], SImode),
+                             rtx_mode_t (operands[2], SImode),
+                             SIGNED, &overflow);
+      emit_move_insn (operands[0], GEN_INT (val.to_shwi ()));
+      if (overflow != wi::OVF_NONE)
+       emit_jump_insn (gen_jump (operands[3]));
+      DONE;
+    }
+  else if (CONST_INT_P (operands[2]))
+    {
+      operands[2] = GEN_INT (-INTVAL (operands[2]));
+      /* Special case for INT_MIN.  */
+      if (INTVAL (operands[2]) == 0x80000000)
+       emit_insn (gen_subvsi3_intmin (operands[0], operands[1]));
+      else
+       emit_insn (gen_addsi3_compareV_imm (operands[0], operands[1],
+                                         operands[2]));
+    }
+  else if (CONST_INT_P (operands[1]))
+    emit_insn (gen_subvsi3_imm1 (operands[0], operands[1], operands[2]));
+  else
+    emit_insn (gen_subvsi3 (operands[0], operands[1], operands[2]));
+
+  arm_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]);
+  DONE;
+})
+
+(define_expand "subvdi4"
+  [(match_operand:DI 0 "s_register_operand")
+   (match_operand:DI 1 "s_register_operand")
+   (match_operand:DI 2 "s_register_operand")
    (match_operand 3 "")]
   "TARGET_32BIT"
 {
-  emit_insn (gen_sub<mode>3_compare1 (operands[0], operands[1], operands[2]));
+  emit_insn (gen_subdi3_compare1 (operands[0], operands[1], operands[2]));
   arm_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]);
 
   DONE;
    (set_attr "type" "alus_sreg")]
 )
 
+(define_insn "subvsi3"
+  [(set (reg:CC_V CC_REGNUM)
+       (compare:CC_V
+        (minus:DI
+         (sign_extend:DI (match_operand:SI 1 "s_register_operand" "l,r"))
+         (sign_extend:DI (match_operand:SI 2 "s_register_operand" "l,r")))
+        (sign_extend:DI (minus:SI (match_dup 1) (match_dup 2)))))
+   (set (match_operand:SI 0 "s_register_operand" "=l,r")
+       (minus:SI (match_dup 1) (match_dup 2)))]
+  "TARGET_32BIT"
+  "subs%?\\t%0, %1, %2"
+  [(set_attr "conds" "set")
+   (set_attr "arch" "t2,*")
+   (set_attr "length" "2,4")
+   (set_attr "type" "alus_sreg")]
+)
+
+(define_insn "subvsi3_imm1"
+  [(set (reg:CC_V CC_REGNUM)
+       (compare:CC_V
+        (minus:DI
+         (match_operand 1 "arm_immediate_operand" "I")
+         (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r")))
+        (sign_extend:DI (minus:SI (match_dup 1) (match_dup 2)))))
+   (set (match_operand:SI 0 "s_register_operand" "=r")
+       (minus:SI (match_dup 1) (match_dup 2)))]
+  "TARGET_32BIT"
+  "rsbs%?\\t%0, %2, %1"
+  [(set_attr "conds" "set")
+   (set_attr "type" "alus_imm")]
+)
+
 (define_insn "subsi3_carryin"
   [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
        (minus:SI (minus:SI (match_operand:SI 1 "reg_or_int_operand" "r,I,Pz")