]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
arm: Fix incorrect modes with 'borrow' operations [PR90311]
authorRichard Earnshaw <rearnsha@arm.com>
Thu, 18 Jul 2019 13:56:52 +0000 (13:56 +0000)
committerRichard Earnshaw <rearnsha@arm.com>
Thu, 5 Mar 2020 17:25:52 +0000 (17:25 +0000)
Looking through the arm backend I noticed that the modes used to pass
comparison types into subtract-with-carry operations were being
incorrectly set.  The result is that the compiler is not truly
self-consistent.  To clean this up I've introduced a new predicate,
arm_borrow_operation (borrowed from the AArch64 backend) which can
match the comparison type with the required mode and then fixed all
the patterns to use this.  The split patterns that were generating
incorrect modes have all obviously been fixed as well.

The basic rule for the use of a borrow is:
- if the condition code was set by a 'subtract-like' operation (subs, cmp),
  then use CCmode and LTU.
- if the condition code was by unsigned overflow of addition (adds), then
  use CC_Cmode and GEU.

gcc:
PR target/90311
Backport from master
* config/arm/predicates.md (arm_borrow_operation): New predicate.
* config/arm/arm.c (subdi3_compare1): Use CCmode for the split.
(arm_subdi3, subdi_di_zesidi, subdi_di_sesidi): Likewise.
(subdi_zesidi_zesidi): Likewise.
(negdi2_compare, negdi2_insn): Likewise.
(negdi_extensidi): Likewise.
(negdi_zero_extendsidi): Likewise.
(arm_cmpdi_insn): Likewise.
(subsi3_carryin): Use arm_borrow_operation.
(subsi3_carryin_const): Likewise.
(subsi3_carryin_const0): Likewise.
(subsi3_carryin_compare): Likewise.
(subsi3_carryin_compare_const): Likewise.
(subsi3_carryin_compare_const0): Likewise.
(subsi3_carryin_shift): Likewise.
(rsbsi3_carryin_shift): Likewise.
(negsi2_carryin_compare): Likewise.

gcc/testsuite:
2020-03-05  Jakub Jelinek  <jakub@redhat.com>

Backport from master
PR target/90311
* gcc.c-torture/execute/pr90311.c: New test.

gcc/ChangeLog
gcc/config/arm/arm.md
gcc/config/arm/predicates.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/pr90311.c [new file with mode: 0644]

index e73e1d0fb2012a213704ae23cde19313f76beb41..306bda13787cf3567bb9c0c4814a6250e99d1965 100644 (file)
@@ -1,3 +1,27 @@
+2020-03-05  Richard Earnshaw  <rearnsha@arm.com>
+
+       PR target/90311
+       Backport from master
+       2019-07-18  Richard Earnshaw  <rearnsha@arm.com>
+
+       * config/arm/predicates.md (arm_borrow_operation): New predicate.
+       * config/arm/arm.c (subdi3_compare1): Use CCmode for the split.
+       (arm_subdi3, subdi_di_zesidi, subdi_di_sesidi): Likewise.
+       (subdi_zesidi_zesidi): Likewise.
+       (negdi2_compare, negdi2_insn): Likewise.
+       (negdi_extensidi): Likewise.
+       (negdi_zero_extendsidi): Likewise.
+       (arm_cmpdi_insn): Likewise.
+       (subsi3_carryin): Use arm_borrow_operation.
+       (subsi3_carryin_const): Likewise.
+       (subsi3_carryin_const0): Likewise.
+       (subsi3_carryin_compare): Likewise.
+       (subsi3_carryin_compare_const): Likewise.
+       (subsi3_carryin_compare_const0): Likewise.
+       (subsi3_carryin_shift): Likewise.
+       (rsbsi3_carryin_shift): Likewise.
+       (negsi2_carryin_compare): Likewise.
+
 2020-03-04  Marek Polacek  <polacek@redhat.com>
 
        Backport from mainline
index efa2d31317ba309d4ea23af88ca13e253eeae521..53e54874c12c9ca8a71599bbef0ef1548d1f24cf 100644 (file)
    (parallel [(set (reg:CC CC_REGNUM)
                   (compare:CC (match_dup 4) (match_dup 5)))
             (set (match_dup 3) (minus:SI (minus:SI (match_dup 4) (match_dup 5))
-                              (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))])]
+                              (ltu:SI (reg:CC CC_REGNUM) (const_int 0))))])]
   {
     operands[3] = gen_highpart (SImode, operands[0]);
     operands[0] = gen_lowpart (SImode, operands[0]);
   [(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")
                            (match_operand:SI 2 "s_register_operand" "r,r,r"))
-                 (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
+                 (match_operand:SI 3 "arm_borrow_operation" "")))]
   "TARGET_32BIT"
   "@
    sbc%?\\t%0, %1, %2
 
 (define_insn "*subsi3_carryin_const"
   [(set (match_operand:SI 0 "s_register_operand" "=r")
-        (minus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "r")
-                           (match_operand:SI 2 "arm_neg_immediate_operand" "L"))
-                  (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
+       (minus:SI (plus:SI
+                  (match_operand:SI 1 "s_register_operand" "r")
+                  (match_operand:SI 2 "arm_neg_immediate_operand" "L"))
+                 (match_operand:SI 3 "arm_borrow_operation" "")))]
   "TARGET_32BIT"
   "sbc\\t%0, %1, #%n2"
   [(set_attr "conds" "use")
 
 (define_insn "*subsi3_carryin_const0"
   [(set (match_operand:SI 0 "s_register_operand" "=r")
-        (minus:SI (match_operand:SI 1 "s_register_operand" "r")
-                  (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
+       (minus:SI (match_operand:SI 1 "s_register_operand" "r")
+                 (match_operand:SI 2 "arm_borrow_operation" "")))]
   "TARGET_32BIT"
   "sbc\\t%0, %1, #0"
   [(set_attr "conds" "use")
 
 (define_insn "*subsi3_carryin_compare"
   [(set (reg:CC CC_REGNUM)
-        (compare:CC (match_operand:SI 1 "s_register_operand" "r")
-                    (match_operand:SI 2 "s_register_operand" "r")))
+       (compare:CC (match_operand:SI 1 "s_register_operand" "r")
+                   (match_operand:SI 2 "s_register_operand" "r")))
    (set (match_operand:SI 0 "s_register_operand" "=r")
-        (minus:SI (minus:SI (match_dup 1)
-                            (match_dup 2))
-                  (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
+       (minus:SI (minus:SI (match_dup 1) (match_dup 2))
+                 (match_operand:SI 3 "arm_borrow_operation" "")))]
   "TARGET_32BIT"
   "sbcs\\t%0, %1, %2"
   [(set_attr "conds" "set")
 
 (define_insn "*subsi3_carryin_compare_const"
   [(set (reg:CC CC_REGNUM)
-        (compare:CC (match_operand:SI 1 "reg_or_int_operand" "r")
-                    (match_operand:SI 2 "const_int_I_operand" "I")))
+       (compare:CC (match_operand:SI 1 "reg_or_int_operand" "r")
+                   (match_operand:SI 2 "const_int_I_operand" "I")))
    (set (match_operand:SI 0 "s_register_operand" "=r")
-        (minus:SI (plus:SI (match_dup 1)
-                           (match_operand:SI 3 "arm_neg_immediate_operand" "L"))
-                  (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
+       (minus:SI (plus:SI
+                  (match_dup 1)
+                  (match_operand:SI 3 "arm_neg_immediate_operand" "L"))
+                 (match_operand:SI 4 "arm_borrow_operation" "")))]
   "TARGET_32BIT
    && (INTVAL (operands[2])
        == trunc_int_for_mode (-INTVAL (operands[3]), SImode))"
 
 (define_insn "*subsi3_carryin_compare_const0"
   [(set (reg:CC CC_REGNUM)
-        (compare:CC (match_operand:SI 1 "reg_or_int_operand" "r")
+       (compare:CC (match_operand:SI 1 "reg_or_int_operand" "r")
                    (const_int 0)))
    (set (match_operand:SI 0 "s_register_operand" "=r")
-        (minus:SI (match_dup 1)
-                  (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
+       (minus:SI (match_dup 1)
+                 (match_operand:SI 2 "arm_borrow_operation" "")))]
   "TARGET_32BIT"
   "sbcs\\t%0, %1, #0"
   [(set_attr "conds" "set")
 (define_insn "*subsi3_carryin_shift"
   [(set (match_operand:SI 0 "s_register_operand" "=r")
        (minus:SI (minus:SI
-                 (match_operand:SI 1 "s_register_operand" "r")
-                  (match_operator:SI 2 "shift_operator"
-                   [(match_operand:SI 3 "s_register_operand" "r")
-                    (match_operand:SI 4 "reg_or_int_operand" "rM")]))
-                 (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
+                  (match_operand:SI 1 "s_register_operand" "r")
+                  (match_operator:SI 2 "shift_operator"
+                   [(match_operand:SI 3 "s_register_operand" "r")
+                    (match_operand:SI 4 "reg_or_int_operand" "rM")]))
+                 (match_operand:SI 5 "arm_borrow_operation" "")))]
   "TARGET_32BIT"
   "sbc%?\\t%0, %1, %3%S2"
   [(set_attr "conds" "use")
    (set_attr "predicable" "yes")
    (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
-                     (const_string "alu_shift_imm")
-                     (const_string "alu_shift_reg")))]
+                                   (const_string "alu_shift_imm")
+                                   (const_string "alu_shift_reg")))]
 )
 
 (define_insn "*rsbsi3_carryin_shift"
   [(set (match_operand:SI 0 "s_register_operand" "=r")
        (minus:SI (minus:SI
-                  (match_operator:SI 2 "shift_operator"
-                   [(match_operand:SI 3 "s_register_operand" "r")
-                    (match_operand:SI 4 "reg_or_int_operand" "rM")])
+                  (match_operator:SI 2 "shift_operator"
+                   [(match_operand:SI 3 "s_register_operand" "r")
+                    (match_operand:SI 4 "reg_or_int_operand" "rM")])
                   (match_operand:SI 1 "s_register_operand" "r"))
-                 (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
+                 (match_operand:SI 5 "arm_borrow_operation" "")))]
   "TARGET_ARM"
   "rsc%?\\t%0, %1, %3%S2"
   [(set_attr "conds" "use")
                   (compare:CC (match_dup 1) (match_dup 2)))
              (set (match_dup 0) (minus:SI (match_dup 1) (match_dup 2)))])
    (set (match_dup 3) (minus:SI (minus:SI (match_dup 4) (match_dup 5))
-                              (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
+                              (ltu:SI (reg:CC CC_REGNUM) (const_int 0))))]
   {
     operands[3] = gen_highpart (SImode, operands[0]);
     operands[0] = gen_lowpart (SImode, operands[0]);
                   (compare:CC (match_dup 1) (match_dup 2)))
              (set (match_dup 0) (minus:SI (match_dup 1) (match_dup 2)))])
    (set (match_dup 3) (minus:SI (match_dup 4)
-                                (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
+                               (ltu:SI (reg:CC CC_REGNUM) (const_int 0))))]
   {
     operands[3] = gen_highpart (SImode, operands[0]);
     operands[0] = gen_lowpart (SImode, operands[0]);
    (set (match_dup 3) (minus:SI (minus:SI (match_dup 4)
                                          (ashiftrt:SI (match_dup 2)
                                                       (const_int 31)))
-                                (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
+                                (ltu:SI (reg:CC CC_REGNUM) (const_int 0))))]
   {
     operands[3] = gen_highpart (SImode, operands[0]);
     operands[0] = gen_lowpart (SImode, operands[0]);
                   (compare:CC (match_dup 2) (match_dup 1)))
              (set (match_dup 0) (minus:SI (match_dup 2) (match_dup 1)))])
    (set (match_dup 3) (minus:SI (minus:SI (const_int 0) (match_dup 4))
-                              (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
+                              (ltu:SI (reg:CC CC_REGNUM) (const_int 0))))]
   {
     operands[3] = gen_highpart (SImode, operands[0]);
     operands[0] = gen_lowpart (SImode, operands[0]);
                                 (ashiftrt:SI (match_dup 2)
                                              (const_int 31))
                                 (match_dup 4))
-                              (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
+                              (ltu:SI (reg:CC CC_REGNUM) (const_int 0))))]
   {
     operands[3] = gen_highpart (SImode, operands[0]);
     operands[0] = gen_lowpart (SImode, operands[0]);
                   (compare:CC (match_dup 1) (match_dup 2)))
              (set (match_dup 0) (minus:SI (match_dup 1) (match_dup 2)))])
    (set (match_dup 3) (minus:SI (minus:SI (match_dup 1) (match_dup 1))
-                              (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
+                              (ltu:SI (reg:CC CC_REGNUM) (const_int 0))))]
   {
        operands[3] = gen_highpart (SImode, operands[0]);
        operands[0] = gen_lowpart (SImode, operands[0]);
             (set (match_dup 2)
                  (minus:SI
                   (minus:SI (const_int 0) (match_dup 3))
-                  (ltu:SI (reg:CC_C CC_REGNUM)
+                  (ltu:SI (reg:CC CC_REGNUM)
                           (const_int 0))))])]
   {
     operands[2] = gen_highpart (SImode, operands[0]);
                   (compare:CC (const_int 0) (match_dup 1)))
              (set (match_dup 0) (minus:SI (const_int 0) (match_dup 1)))])
    (set (match_dup 2) (minus:SI (minus:SI (const_int 0) (match_dup 3))
-                                (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
+                                (ltu:SI (reg:CC CC_REGNUM) (const_int 0))))]
   {
     operands[2] = gen_highpart (SImode, operands[0]);
     operands[0] = gen_lowpart (SImode, operands[0]);
    (set (match_operand:SI 0 "s_register_operand" "=r")
        (minus:SI (minus:SI (const_int 0)
                            (match_dup 1))
-                 (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
+                 (match_operand:SI 2 "arm_borrow_operation" "")))]
   "TARGET_ARM"
   "rscs\\t%0, %1, #0"
   [(set_attr "conds" "set")
                asr     Rhi, Rin, #31
                rsbs    Rlo, Rin, #0
                rsc     Rhi, Rhi, #0 (thumb2: sbc Rhi, Rhi, Rhi, lsl #1).  */
-       rtx cc_reg = gen_rtx_REG (CC_Cmode, CC_REGNUM);
+       rtx cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
 
        emit_insn (gen_rtx_SET (high,
                                gen_rtx_ASHIFTRT (SImode, operands[1],
       ;; since we just need to propagate the carry.
   "&& reload_completed"
   [(parallel [(set (reg:CC CC_REGNUM)
-                   (compare:CC (const_int 0) (match_dup 1)))
-              (set (match_dup 0) (minus:SI (const_int 0) (match_dup 1)))])
+                  (compare:CC (const_int 0) (match_dup 1)))
+             (set (match_dup 0) (minus:SI (const_int 0) (match_dup 1)))])
    (set (match_dup 2) (minus:SI (minus:SI (match_dup 2) (match_dup 2))
-                                (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
+                               (ltu:SI (reg:CC CC_REGNUM) (const_int 0))))]
   {
     operands[2] = gen_highpart (SImode, operands[0]);
     operands[0] = gen_lowpart (SImode, operands[0]);
   "#"   ; "cmp\\t%Q0, %Q1\;sbcs\\t%2, %R0, %R1"
   "&& reload_completed"
   [(set (reg:CC CC_REGNUM)
-        (compare:CC (match_dup 0) (match_dup 1)))
+       (compare:CC (match_dup 0) (match_dup 1)))
    (parallel [(set (reg:CC CC_REGNUM)
-                   (compare:CC (match_dup 3) (match_dup 4)))
-              (set (match_dup 2)
-                   (minus:SI (match_dup 5)
-                            (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))])]
+                  (compare:CC (match_dup 3) (match_dup 4)))
+             (set (match_dup 2)
+                  (minus:SI (match_dup 5)
+                            (ltu:SI (reg:CC CC_REGNUM) (const_int 0))))])]
   {
     operands[3] = gen_highpart (SImode, operands[0]);
     operands[0] = gen_lowpart (SImode, operands[0]);
index f53378a250edfdd0de467f2abbe08bc933d6d734..25f86471ded9682f4f63861936c8b7c9a26c6c57 100644 (file)
 (define_special_predicate "lt_ge_comparison_operator"
   (match_code "lt,ge"))
 
+;; Match a "borrow" operation for use with SBC.  The precise code will
+;; depend on the form of the comparison.  This is generally the inverse of
+;; a carry operation, since the logic of SBC uses "not borrow" in it's
+;; calculation.
+(define_special_predicate "arm_borrow_operation"
+  (match_code "geu,ltu")
+  {
+    if (XEXP (op, 1) != const0_rtx)
+      return false;
+    rtx op0 = XEXP (op, 0);
+    if (!REG_P (op0) || REGNO (op0) != CC_REGNUM)
+      return false;
+    machine_mode ccmode = GET_MODE (op0);
+    if (ccmode == CC_Cmode)
+      return GET_CODE (op) == GEU;
+    else if (ccmode == CCmode)
+      return GET_CODE (op) == LTU;
+    return false;
+  }
+)
+
 ;; The vsel instruction only accepts the ARM condition codes listed below.
 (define_special_predicate "arm_vsel_comparison_operator"
   (and (match_operand 0 "expandable_comparison_operator")
index 720fa1ec987e4b6d06321ce024f87db56a754c37..84b25c6e9f59f56beb98de6292b5fe168bab7ff5 100644 (file)
@@ -1,3 +1,9 @@
+2020-03-05  Jakub Jelinek  <jakub@redhat.com>
+
+       Backport from master
+       PR target/90311
+       * gcc.c-torture/execute/pr90311.c: New test.
+
 2020-03-05  Uroš Bizjak  <ubizjak@gmail.com>
 
        * g++.dg/asan/asan_test.C (dg-options): Add
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr90311.c b/gcc/testsuite/gcc.c-torture/execute/pr90311.c
new file mode 100644 (file)
index 0000000..af8cde6
--- /dev/null
@@ -0,0 +1,16 @@
+/* PR rtl-optimization/90311 */
+
+int a, b;
+
+int
+main ()
+{
+  unsigned long long x;
+  unsigned int c;
+  __builtin_add_overflow ((unsigned char) a, b, &c);
+  b -= c < (unsigned char) a;
+  x = b;
+  if (x)
+    __builtin_abort ();
+  return 0;
+}