aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2025-08-07 22:48:52 +0000
committerRichard Henderson <richard.henderson@linaro.org>2025-08-11 23:25:10 +0000
commitafd6aa80b373fdf4de6bd3ac3c5f099634ac26e2 (patch)
tree8a7269af5a8913ac7d933065b694017db50ffdd7 /gcc
parent2af897e11b358fccb978e3a96b2899ce193bcd25 (diff)
downloadgcc-afd6aa80b373fdf4de6bd3ac3c5f099634ac26e2.zip
gcc-afd6aa80b373fdf4de6bd3ac3c5f099634ac26e2.tar.gz
gcc-afd6aa80b373fdf4de6bd3ac3c5f099634ac26e2.tar.bz2
aarch64: CMPBR branches must be invertable
Restrict the immediate range to the intersection of LT/GE and GT/LE so that cfglayout can invert the condition to redirect any branch. gcc: PR target/121388 * config/aarch64/aarch64.cc (aarch64_cb_rhs): Restrict the range of LT/GE and GT/LE to their intersections. * config/aarch64/aarch64.md (*aarch64_cb<INT_CMP><GPI>): Unexport. Use cmpbr_imm_predicate instead of aarch64_cb_rhs. * config/aarch64/constraints.md (Uc1): Accept 0..62. (Uc2): Remove. * config/aarch64/iterators.md (cmpbr_imm_predicate): New. (cmpbr_imm_constraint): Update to match aarch64_cb_rhs. * config/aarch64/predicates.md (aarch64_cb_reg_i63_operand): New. (aarch64_cb_reg_i62_operand): New. gcc/testsuite: PR target/121388 * gcc.target/aarch64/cmpbr.c (u32_x0_ult_64): XFAIL. (i32_x0_slt_64, u64_x0_ult_64, i64_x0_slt_64): XFAIL. * gcc.target/aarch64/cmpbr-2.c: New.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/aarch64/aarch64.cc23
-rw-r--r--gcc/config/aarch64/aarch64.md28
-rw-r--r--gcc/config/aarch64/constraints.md10
-rw-r--r--gcc/config/aarch64/iterators.md20
-rw-r--r--gcc/config/aarch64/predicates.md10
-rw-r--r--gcc/testsuite/gcc.target/aarch64/cmpbr-2.c110
-rw-r--r--gcc/testsuite/gcc.target/aarch64/cmpbr.c8
7 files changed, 162 insertions, 47 deletions
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index e4a9e87..039f196 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -975,19 +975,24 @@ aarch64_cb_rhs (rtx_code op_code, rtx rhs)
{
case EQ:
case NE:
- case GT:
- case GTU:
case LT:
case LTU:
+ case GE:
+ case GEU:
+ /* EQ/NE range is 0 .. 63.
+ LT/LTU range is 0 .. 63.
+ GE/GEU range is 1 .. 64 => GT x - 1, but also supports 0 via XZR.
+ So the intersection is 0 .. 63. */
return IN_RANGE (rhs_val, 0, 63);
- case GE: /* CBGE: signed greater than or equal */
- case GEU: /* CBHS: unsigned greater than or equal */
- return IN_RANGE (rhs_val, 1, 64);
-
- case LE: /* CBLE: signed less than or equal */
- case LEU: /* CBLS: unsigned less than or equal */
- return IN_RANGE (rhs_val, -1, 62);
+ case GT:
+ case GTU:
+ case LE:
+ case LEU:
+ /* GT/GTU range is 0 .. 63
+ LE/LEU range is -1 .. 62 => LT x + 1.
+ So the intersection is 0 .. 62. */
+ return IN_RANGE (rhs_val, 0, 62);
default:
return false;
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 54389e9..77b4bdc 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -865,21 +865,21 @@
;; Emit a `CB<cond> (register)` or `CB<cond> (immediate)` instruction.
;; The immediate range depends on the comparison code.
-;; Comparisons against immediates outside this range fall back to
-;; CMP + B<cond>.
-(define_insn "aarch64_cb<INT_CMP:code><GPI:mode>"
- [(set (pc) (if_then_else (INT_CMP
- (match_operand:GPI 0 "register_operand" "r")
- (match_operand:GPI 1 "nonmemory_operand"
- "r<INT_CMP:cmpbr_imm_constraint>"))
- (label_ref (match_operand 2))
- (pc)))]
- "TARGET_CMPBR && aarch64_cb_rhs (<INT_CMP:CODE>, operands[1])"
+(define_insn "*aarch64_cb<code><mode>"
+ [(set (pc) (if_then_else
+ (INT_CMP
+ (match_operand:GPI 0 "register_operand" "r")
+ (match_operand:GPI 1
+ "aarch64_reg_<cmpbr_imm_constraint>_operand"
+ "r<cmpbr_imm_constraint>"))
+ (label_ref (match_operand 2))
+ (pc)))]
+ "TARGET_CMPBR"
{
- return (get_attr_far_branch (insn) == FAR_BRANCH_NO)
- ? "cb<INT_CMP:cmp_op>\\t%<w>0, %<w>1, %l2"
- : aarch64_gen_far_branch (operands, 2, "L",
- "cb<INT_CMP:inv_cmp_op>\\t%<w>0, %<w>1, ");
+ if (get_attr_length (insn) == 4)
+ return "cb<cmp_op>\t%<w>0, %<w>1, %l2";
+ return aarch64_gen_far_branch (operands, 2, "L",
+ "cb<inv_cmp_op>\t%<w>0, %<w>1, ");
}
[(set_attr "type" "branch")
(set (attr "length")
diff --git a/gcc/config/aarch64/constraints.md b/gcc/config/aarch64/constraints.md
index dc1925d..7b9e558 100644
--- a/gcc/config/aarch64/constraints.md
+++ b/gcc/config/aarch64/constraints.md
@@ -312,15 +312,9 @@
(define_constraint "Uc1"
"@internal
- A constraint that matches the integers 1...64."
+ A constraint that matches the integers 0...62."
(and (match_code "const_int")
- (match_test "IN_RANGE (ival, 1, 64)")))
-
-(define_constraint "Uc2"
- "@internal
- A constraint that matches the integers -1...62."
- (and (match_code "const_int")
- (match_test "IN_RANGE (ival, -1, 62)")))
+ (match_test "IN_RANGE (ival, 0, 62)")))
(define_constraint "Up3"
"@internal
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index 68b080d..c3771d9 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -2986,19 +2986,15 @@
(define_code_iterator INT_CMP [lt le eq ne ge gt ltu leu geu gtu])
+;; Inverse comparisons must have the same constraint so that
+;; branches can be redirected during late compilation.
(define_code_attr cmpbr_imm_constraint [
- (eq "Uc0")
- (ne "Uc0")
- (gt "Uc0")
- (gtu "Uc0")
- (lt "Uc0")
- (ltu "Uc0")
-
- (ge "Uc1")
- (geu "Uc1")
-
- (le "Uc2")
- (leu "Uc2")
+ (eq "Uc0") (ne "Uc0")
+ (lt "Uc0") (ge "Uc0")
+ (ltu "Uc0") (geu "Uc0")
+
+ (gt "Uc1") (le "Uc1")
+ (gtu "Uc1") (leu "Uc1")
])
(define_code_attr fix_trunc_optab [(fix "fix_trunc")
diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md
index af6f00e..42304ce 100644
--- a/gcc/config/aarch64/predicates.md
+++ b/gcc/config/aarch64/predicates.md
@@ -1089,3 +1089,13 @@
(define_special_predicate "aarch64_ptrue_all_operand"
(and (match_code "const_vector")
(match_test "aarch64_ptrue_all_mode (op) == mode")))
+
+(define_predicate "aarch64_reg_Uc0_operand"
+ (ior (match_operand 0 "register_operand")
+ (and (match_code "const_int")
+ (match_test "satisfies_constraint_Uc0 (op)"))))
+
+(define_predicate "aarch64_reg_Uc1_operand"
+ (ior (match_operand 0 "register_operand")
+ (and (match_code "const_int")
+ (match_test "satisfies_constraint_Uc1 (op)"))))
diff --git a/gcc/testsuite/gcc.target/aarch64/cmpbr-2.c b/gcc/testsuite/gcc.target/aarch64/cmpbr-2.c
new file mode 100644
index 0000000..2c2764f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/cmpbr-2.c
@@ -0,0 +1,110 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* PR target/121388 */
+
+#pragma GCC target "+cmpbr"
+
+extern int a, b, s;
+typedef struct {
+ unsigned long d[2];
+} g;
+typedef struct {
+ long d[4];
+} h;
+typedef struct {
+ unsigned long d[];
+} j;
+typedef struct {
+ long d[];
+} k;
+typedef union {
+ struct {
+ short l;
+ unsigned m;
+ } i;
+ long double f;
+} n;
+g o[] = {{}};
+const g aa[1];
+h ab, t;
+h ac[1];
+long p, r, ae, af, ag, ah, aj, ak, al, an, ao, aq, ar, aw, ax, ba, bb, bc, bd;
+unsigned long q, am, ay, w;
+g ad;
+unsigned ai, ap, at, au, av, az;
+short as, v, be;
+long double u;
+double f() {
+ long bf;
+ g c;
+ unsigned long bg;
+ int e, bh;
+ j x;
+ if (q << 61 == 3ull << 61) {
+ if (q & 58) {
+ return u;
+ }
+ as = 8;
+ return a;
+ }
+ e = c.d[1] = q & ((1ull << 49) - 1);
+ bg = p;
+ if (101086242752 < c.d[1] ||
+ (101086242752 == c.d[1] && 4003012203950112767 < p))
+ c.d[1] = p;
+ if (c.d[1] && p == 0) {
+ n bi;
+ bi.i.l = be;
+ return bi.f;
+ }
+ s = c.d[1] == 0 ? p ?: p : __builtin_clzll(c.d[1]);
+ s == 0 ? c.d[1] : s >= 64 ? c.d[1] : (c.d[1] = s, bg = 0);
+ if (e >= 3) {
+ if (a) {
+ n bi;
+ bi.i.m = 0;
+ return bi.f;
+ }
+ return ar;
+ }
+ if (e <= -4985)
+ e = 4985;
+ ad = (aa + 5)[e];
+ bh = s;
+ if (r && (bg = 0))
+ t = ab;
+ t = ac[e];
+ k bj, bk;
+ ao = bg;
+ az = bg;
+ al = az;
+ ay = aw = bg >> 2;
+ b = ay + (aq > 2) < bg * ap;
+ ay = az;
+ bd = av = w;
+ ah = bb;
+ bj.d[4] = am;
+ an = c.d[1] >> an;
+ ax = bg * az;
+ aj = t.d[1];
+ az = w = ax;
+ bb = az;
+ ag = aj;
+ long bl = af = w + az < w;
+ au = aw;
+ am = au < w || w < ak + am;
+ bk.d[3] = bl + az;
+ ai = a < aj;
+ at = aj + b < ai;
+ x.d[3] = ba;
+ bc = bk.d[3] + bc + bj.d[4];
+ bf = ae;
+ if (x.d[3] || o[bf & 1].d[0]) {
+ if (bf == 0)
+ ;
+ else if (bf == 3 && bh)
+ if ((a & 3 && x.d[3] < 3ull << 62) || (q && x.d[3]))
+ b = 6;
+ }
+ return a;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/cmpbr.c b/gcc/testsuite/gcc.target/aarch64/cmpbr.c
index 853a1e6..23f462f 100644
--- a/gcc/testsuite/gcc.target/aarch64/cmpbr.c
+++ b/gcc/testsuite/gcc.target/aarch64/cmpbr.c
@@ -1273,7 +1273,7 @@ FAR_BRANCH(u64, 42);
*/
/*
-** u32_x0_ult_64:
+** u32_x0_ult_64: { xfail *-*-* }
** cbhi w0, 63, .L([0-9]+)
** b taken
** .L\1:
@@ -1308,7 +1308,7 @@ FAR_BRANCH(u64, 42);
*/
/*
-** i32_x0_slt_64:
+** i32_x0_slt_64: { xfail *-*-* }
** cbgt w0, 63, .L([0-9]+)
** b taken
** .L\1:
@@ -1361,7 +1361,7 @@ FAR_BRANCH(u64, 42);
*/
/*
-** u64_x0_ult_64:
+** u64_x0_ult_64: { xfail *-*-* }
** cbhi x0, 63, .L([0-9]+)
** b taken
** .L\1:
@@ -1396,7 +1396,7 @@ FAR_BRANCH(u64, 42);
*/
/*
-** i64_x0_slt_64:
+** i64_x0_slt_64: { xfail *-*-* }
** cbgt x0, 63, .L([0-9]+)
** b taken
** .L\1: