combine's distribute_and_simplify_rtx distributes (and (xor B C) (not A))
to (xor (ior A B) (ior A C)), thereby duplicating A. When A is a
paradoxical subreg that is spilled the two As can have differing values
which now spill into the result as we can no longer rely on the
XOR/IOR combination to cancel out those bits.
Bootstrapped and tested on x86_64-unknown-linux-gnu.
In the bugzilla audit trail Uros mentions that LRA should spill/reload
paradoxical subregs inconsistently:
Yes it is LRA. Before LRA we have:
(insn 219 218 220 3 (parallel [
(set (reg:SI 146 [ _47 ])
(xor:SI (reg:SI 343 [ df_91 ])
(subreg:SI (reg/v:QI 160 [ dl ]) 0)))
(clobber (reg:CC 17 flags))
]) "pr127606.c":180:13 860 {*xorsi_1}
(expr_list:REG_DEAD (reg:SI 343 [ df_91 ])
(expr_list:REG_UNUSED (reg:CC 17 flags)
(nil))))
Which LRA transforms to:
(insn 380 381 365 3 (set (mem/c:QI (plus:DI (reg/f:DI 7 sp)
(const_int 4 [0x4])) [11 %sfp+-52 S1 A32])
(reg/v:QI 4 si [orig:160 dl ] [160])) "pr127606.c":180:13 102
{*movqi_internal}
(nil))
(insn 365 380 219 3 (set (reg:SI 2 cx [410])
(mem/c:SI (plus:DI (reg/f:DI 7 sp)
(const_int 4 [0x4])) [11 %sfp+-52 S4 A32]))
"pr127606.c":180:13 100 {*movsi_internal}
(nil))
(insn 219 365 220 3 (parallel [
(set (reg:SI 1 dx [orig:146 _47 ] [146])
(xor:SI (reg:SI 1 dx [orig:343 df_91 ] [343])
(reg:SI 2 cx [410])))
(clobber (reg:CC 17 flags))
]) "pr127606.c":180:13 860 {*xorsi_1}
(nil))
spilling in QImode and reloading in SImode. Iff to be fixed in
LRA then I think the undefined bits would have to be spilled
and reloaded to guarantee that two uses of the "same" paradoxical
pseudo remain equal.
Vlad says this is entirely undefined but I agree the above is
quite unfortunate (and also bad for performance - a store in
QImode does not forward to a load in SImode).
Jeff/Eric, maybe you know whether it's usual to fend off against
paradoxical subregs for these kind of transforms.
Vlad - I think it's worth fixing the STLF issue and consistently
handle spill/reload -- I'd say spilling/reloading only the
defined parts is OK, but it wouldn't fix things. spilling/reloading
up to word_mode undefined bits might be another good option
(not sure if we have, say paradoxical XImode ops that we can't spill
because of lack of move instructions).
Richard.
PR rtl-optimization/127606
* combine.cc (distribute_and_simplify_rtx): Gate the
(and (xor B C) (not A)) to (xor (ior A B) (ior A C))
distribution on A not containing a paradoxical subreg.
* gcc.dg/pr127606.c: New testcase.
---
gcc/combine.cc | 6 +-
gcc/testsuite/gcc.dg/pr127606.c | 272 ++++++++++++++++++++++++++++++++
2 files changed, 277 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/gcc.dg/pr127606.c
diff --git a/gcc/combine.cc b/gcc/combine.cc
index 11427f5a920..42953081684 100644
--- a/gcc/combine.cc
+++ b/gcc/combine.cc
@@ -10070,7 +10070,11 @@ distribute_and_simplify_rtx (rtx x, int n)
/* Special case (and (xor B C) (not A)), which is equivalent to
(xor (ior A B) (ior A C)) */
- if (outer_code == AND && inner_code == XOR && GET_CODE (distributed) == NOT)
+ if (outer_code == AND && inner_code == XOR && GET_CODE (distributed) == NOT
+ /* But not when A is a paradoxical subreg since the masking effect
+ of the outer AND is lost and the duplicated use can result in
+ undefined bits to be exposed when spilling. */
+ && !contains_paradoxical_subreg_p (XEXP (distributed, 0)))
{
distributed = XEXP (distributed, 0);
outer_code = IOR;
diff --git a/gcc/testsuite/gcc.dg/pr127606.c b/gcc/testsuite/gcc.dg/pr127606.c
new file mode 100644
index 00000000000..a9249e07d8b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr127606.c
@@ -0,0 +1,272 @@
+/* { dg-do run { target lp64 } } */
+/* { dg-options "-O3 -fno-guess-branch-probability -fno-tree-loop-im
-fno-tree-pre -fno-forward-propagate -fno-ipa-ra -fno-tree-ch" } */
+
+struct a {
+ short d[2];
+};
+short m, d, p, aa, ab = -101, ac = -10493, ad = -65, ae, af = -15067, ag, t,
ah,
+ z, ai, *aj, **ak;
+int n, q, r = -66, al, am = -781047284, an, ao = -39, ap, aq, ar, as, at, au,
+ av, aw, u, ax, w, ay, az, ba, bb, bc, bd = -284627199, be, bf, bg,
bh,
+ bi, bj, bk, bl, *bm, **bn;
+long e, f, bo, bp = -342246050408, bq, br, bs, bt, bu, bv, bw, bx, by, bz,
+ ca = 6, cb, cc, cd, *ce, *cf, *cg, *ch, *ci, *cj;
+float l, o = -3.75f, s;
+char ck, v, cl;
+__attribute__((noinline)) int cm(int cn, int co) {
+ static int g[256];
+ for (int h = 0; h < 256; ++h) {
+ unsigned c = h;
+ for (int i = 0; i < 8; ++i)
+ c = c & 1 ? c >> 1 ^ 3988292384 : c >> 1;
+ g[h] = c;
+ }
+ unsigned j = cn;
+ int k = co;
+ for (int b = 0; b < 4; ++b) {
+ char a = k;
+ k >>= 8;
+ j = j >> 8 ^ g[(j ^ a) & 255];
+ }
+ return j;
+}
+void cp(long, int, long);
+int cq(short p1, short p2, int cr, int cs, short ct) {
+ m = n = cm(0, (unsigned long)cr << 40 >> 40);
+ n = cm(n, 0);
+ n = cm(n, cs);
+ n = cm(n, (unsigned long)ct >> 52);
+ n = cm(n, 0);
+ n = cm(n, 93);
+ n = cm(n, 0);
+ return n;
+}
+void cu(char);
+int cv(int cn) {
+ cm(0, 0);
+ cm(0, cn);
+ return 0;
+}
+int cw(int, char, float, char, char, char, short);
+int cx(short cn, char co, float cr) {
+ short cy = -3410;
+ ak = &aj;
+ ce = &e;
+ d = cn - -32563;
+ q = 1083998199 - 1083474983 + 16;
+ f = -1074528307 - ((long)((unsigned long)cy << 48) >> 48);
+ *ce = 1073609055;
+ l = -84541440;
+ s = 8.0f * cr;
+ *ak = &p;
+ cy = -16400;
+ *aj = 267 - cn;
+ al = cm(0, d);
+ al = cm(al, (long)((unsigned long)cy << 48) >> 48);
+ al = cm(al, e);
+ al = cm(al, 0);
+ al = cm(al, f);
+ al = cm(al, 1.5f);
+ al = cm(al, 0);
+ al = cm(al, o);
+ al = cm(al, 3.0f);
+ al = cm(al, 1.5f);
+ al = cm(al, 0);
+ al = cm(al, 1.0f);
+ al = cm(al, l);
+ al = cm(al, 84933729);
+ al = cm(al, p);
+ al = cm(al, r);
+ al = cm(al, q);
+ al = cm(al, s);
+ al = cm(al, 0);
+ al = cm(al, (long)((unsigned long)cn << 48) >> 48);
+ al = cm(al, co);
+ al = cm(al, 0);
+ al = cm(al, 0);
+ al = cm(al, 0);
+ al = cm(al, 0);
+ al = cm(al, 0);
+ al = cm(al, 0);
+ al = cm(al, 0);
+ aa = *aj;
+ al = cm(al, aa);
+ bo = *ce;
+ al = cm(al, bo);
+ return al;
+}
+int cz(int cn, short co, long cr, int cs, long ct, short da, int db) {
+ long dc = 17;
+ cf = cg = ch = &dc;
+ *cg = dc + dc;
+ ae = co - 9 * co;
+ an = -368690105 - -2048327106;
+ ap = cm(0, (long)((unsigned long)ad << 52) >> 52);
+ ap = cm(ap, (long)((unsigned long)ab << 52) >> 52);
+ ap = cm(ap, 11);
+ ap = cm(ap, 25022);
+ ap = cm(ap, (long)((unsigned long)ac << 48) >> 48);
+ ap = cm(ap, 261555065);
+ ap = cm(ap, 29095);
+ ap = cm(ap, ct);
+ ap = cm(ap, dc);
+ ap = cm(ap, (long)((unsigned long)ae << 48) >> 48);
+ ap = cm(ap, (long)((unsigned long)af << 48) >> 48);
+ ap = cm(ap, 0);
+ ap = cm(ap, am);
+ ap = cm(ap, 14);
+ ap = cm(ap, -712613994);
+ ap = cm(ap, -591966605);
+ ap = cm(ap, bp);
+ ap = cm(ap, an);
+ ap = cm(ap, ao);
+ ap = cm(ap, 4.0);
+ ap = cm(ap, cn);
+ ap = cm(ap, co);
+ ap = cm(ap, cr);
+ ap = cm(ap, (long)((unsigned long)cs << 44) >> 44);
+ ap = cm(ap, ct);
+ ap = cm(ap, (long)((unsigned long)da << 52) >> 52);
+ ap = cm(ap, 0);
+ ap = cm(ap, db);
+ bq = *cf;
+ ap = cm(ap, bq);
+ br = *cg;
+ ap = cm(ap, br);
+ bs = *ch;
+ ap = cm(ap, bs);
+ return ap;
+}
+void dd(long cn) {
+ bv = 1837996544 + cn;
+ bw = bv % 3037000493;
+ by = 1487194 * cn;
+ bx = by % 3037000493;
+ by = 1944416850 * bw % 3037000493;
+ bx = bx + by;
+ cp(bx, 3, -1);
+}
+void cp(long cn, int co, long cr) {
+ int x, de, df, dg = 0, dh, di = 11, dj, *dk;
+ char dl = 0, dm, y, dn, dp;
+ long dq = -82;
+ struct a dr = {{0,0}};
+ short ds = 0, dt = 0, du;
+ dk = &u;
+ do {
+ dh = cn;
+ aw = dh % 46337;
+ w = 40033 * aw;
+ au = w + 31847;
+ au = au % 46337;
+ ck = (long)((unsigned long)dq << 16) >> 16;
+ av = ck % di + 11;
+ av = av % di;
+ v = 2 * av % di;
+ dm = cn;
+ y = dm % di + 11;
+ y = y % di;
+ dp = 10 * y % di;
+ dn = dp + 4;
+ t = 45 * cr;
+ dj = cw(au - 20753 + 2050618351, -111, -1044328.0f, v - 6 - 104, dn - 5,
+ -19, t) -
+ 95733627;
+ ag = (unsigned long)dq << 16 >> 6;
+ ds = ds + dt;
+ ds = ds % 81;
+ dt = 98 * ag;
+ du = dr.d[0];
+ de = (long)dl << 40 >> 40;
+ aq = 30 ^ de;
+ df = 127 ^ de;
+ aq = aq & df;
+ ar = cq(ds, du, -4079617 ^ aq, 54, -1) - 2032857596;
+ *dk = dj - ar;
+ x = (21 >> co) + ~u;
+ dr.d[0] = 6;
+ if (0 <= dl - 31) {
+ dq = cr;
+ ax = -10 * co;
+ dg = dg + 9;
+ at = cv(dg - 7) - 309410;
+ u = co + at;
+ }
+ dl = 127;
+ } while (0 <= u);
+ as = 10 + x;
+ cu(as - 10 - 1);
+}
+void cu(char cn) {
+ bb = cw(2050618351, -111, -1044328.0f, cn - 103, -72, -19, 136) + 979061894;
+ ba = 130280446 + bb;
+ if (-2 * ba != -262668294)
+ az = 1067210928 / ay;
+}
+int cw(int cn, char co, float cr, char cs, char ct, char da, short db) {
+ long dv = -197;
+ ci = &ca;
+ bn = &bm;
+ cj = &cb;
+ *cj = -66322669 - dv;
+ ah = 2048 - -79 - 2048;
+ do {
+ *ci = ~dv + (ca <= 0 ? 1008729983 : -1039925336);
+ z = ah - 21 * ah - 3 * ah;
+ dv = cb + *ci;
+ bh = 128 + 126 - 95 / da;
+ bk = cx(-16164, 121, -0.5f) - 826019009;
+ bi = bk + cn;
+ bm = &bf;
+ } while (8 < -ca);
+ *bm = (long)((unsigned long)da << 56) >> 56;
+ *cj = ca - 2116026151;
+ cl = da - 75;
+ *bn = &bi;
+ bg = da - 57 + ~cs;
+ be = 1991637 * bi - -2146475557 - 2129375996;
+ bc = -7342433 - ((long)((unsigned long)2048 << 52) >> 52);
+ ai = -257 + 32765 + db;
+ bz = 376721798 - 2146435071 / ca;
+ dv = -6029336;
+ ca = 97517562 - -10 * cb;
+ bl = cz(-1309835519, 2167, 663091339, -34828, 70368711542989, z - 206,
+ -1040119841) -
+ 498025;
+ bj = cm(0, (long)((unsigned long)bc << 40) >> 40);
+ bj = cm(bj, (long)((unsigned long)z << 52) >> 52);
+ bj = cm(bj, bz);
+ bj = cm(bj, be);
+ bj = cm(bj, ai);
+ bj = cm(bj, bd);
+ bj = cm(bj, bf);
+ bj = cm(bj, ca);
+ bj = cm(bj, (long)((unsigned long)cl << 56) >> 56);
+ bj = cm(bj, 3);
+ bj = cm(bj, (unsigned long)bh << 56 >> 56);
+ bj = cm(bj, bg);
+ bj = cm(bj, 67);
+ bj = cm(bj, dv);
+ bj = cm(bj, cb);
+ bj = cm(bj, bi);
+ bj = cm(bj, bl);
+ bj = cm(bj, (long)((unsigned long)co << 56) >> 56);
+ bj = cm(bj, cr);
+ bj = cm(bj, 0);
+ bj = cm(bj, (long)((unsigned long)cs << 56) >> 56);
+ bj = cm(bj, (long)((unsigned long)ct << 56) >> 56);
+ bj = cm(bj, (long)((unsigned long)da << 56) >> 56);
+ bj = cm(bj, (unsigned long)db << 48 >> 48);
+ cc = *ci;
+ bj = cm(bj, cc);
+ cd = *cj;
+ bj = cm(bj, cd);
+ bj = cm(bj, *bm);
+ return bj;
+}
+int main() {
+ bt = 1316079754;
+ bu = 2397044987 * 111;
+ bt = bt + bu;
+ dd(bt);
+}
--
2.51.0