Hi everybody,
I'm working on a pass for the CLI back-end which 'simplifies' GIMPLE code before
entering the tree-ssa passes in order to simplify and improva CLI emission by
removing or simplifying nodes which don't have a corresponding straightforward
implementation in CLI. The pass runs between pass_lower_eh and pass_build_cfg
and replaces some GIMPLE nodes with more-or-less arbitrary GIMPLE.
However a problem has arisen when I replace COMPONENT_REFs accessing
bit-fields with explicit load-mask or load-mask-store sequences, it seems that
GCC loses track of pointer aliasing, here's an example from the testsuite
(gcc.dg/tree-ssa/alias-14.c compiled with -O2). The original code is:
struct s
{
long long a:12;
long long b:12;
long long c:40;
};
struct s s, *p = &s;
int
main ()
{
p->a = 1;
s.a = 0;
s.b = 0;
return p->a + s.b;
}
What gets out of lower_eh is this:
main ()
{
int D.1519;
<unnamed-signed:12> D.1518;
int D.1517;
<unnamed-signed:12> D.1516;
int D.1515;
struct s * p.0;
p.0 = p;
p.0->a = 1;
s.a = 0;
s.b = 0;
p.0 = p;
D.1516 = p.0->a;
D.1517 = (int) D.1516;
D.1518 = s.b;
D.1519 = (int) D.1518;
D.1515 = D.1517 + D.1519;
goto <D1521>;
<D1521>:;
return D.1515;
}
which my pass turns main() into this:
;; Function main (main)
main ()
{
struct s * cilsimp.18;
long long int * cilsimp.17;
long long int cilsimp.16;
struct s * cilsimp.15;
long long int * cilsimp.14;
long long int cilsimp.13;
struct s * cilsimp.12;
long long int * cilsimp.11;
long long int cilsimp.10;
long long int cilsimp.9;
struct s * cilsimp.8;
long long int * cilsimp.7;
long long int cilsimp.6;
long long int cilsimp.5;
struct s * cilsimp.4;
long long int * cilsimp.3;
long long int cilsimp.2;
long long int cilsimp.1;
int D.1519;
<unnamed-signed:12> D.1518;
int D.1517;
<unnamed-signed:12> D.1516;
int D.1515;
struct s * p.0;
p.0 = p;
cilsimp.4 = p.0;
cilsimp.3 = (long long int *) cilsimp.4;
cilsimp.1 = *cilsimp.3;
cilsimp.1 = cilsimp.1 & -4096;
cilsimp.1 = cilsimp.1 | 1;
*cilsimp.3 = cilsimp.1;
cilsimp.8 = &s;
cilsimp.7 = (long long int *) cilsimp.8;
cilsimp.5 = *cilsimp.7;
cilsimp.5 = cilsimp.5 & -4096;
cilsimp.5 = cilsimp.5 | 0;
*cilsimp.7 = cilsimp.5;
cilsimp.12 = &s;
cilsimp.11 = (long long int *) cilsimp.12;
cilsimp.9 = *cilsimp.11;
cilsimp.9 = cilsimp.9 & -16773121;
cilsimp.9 = cilsimp.9 | 0;
*cilsimp.11 = cilsimp.9;
p.0 = p;
cilsimp.15 = p.0;
cilsimp.14 = (long long int *) cilsimp.15;
cilsimp.13 = *cilsimp.14;
cilsimp.13 = cilsimp.13 << 52;
cilsimp.13 = cilsimp.13 >> 52;
D.1516 = (<unnamed-signed:12>) cilsimp.13;
D.1517 = (int) D.1516;
cilsimp.18 = &s;
cilsimp.17 = (long long int *) cilsimp.18;
cilsimp.16 = *cilsimp.17;
cilsimp.16 = cilsimp.16 << 40;
cilsimp.16 = cilsimp.16 >> 52;
D.1518 = (<unnamed-signed:12>) cilsimp.16;
D.1519 = (int) D.1518;
D.1515 = D.1517 + D.1519;
goto <D1521>;
<D1521>:;
return D.1515;
}
... and later FRE into this:
main ()
{
long long int * cilsimp.17;
long long int cilsimp.16;
struct s * cilsimp.15;
long long int * cilsimp.14;
long long int cilsimp.13;
long long int * cilsimp.11;
long long int cilsimp.9;
long long int * cilsimp.7;
long long int cilsimp.5;
struct s * cilsimp.4;
long long int * cilsimp.3;
long long int cilsimp.1;
int D.1519;
<unnamed-signed:12> D.1518;
int D.1517;
<unnamed-signed:12> D.1516;
int D.1515;
<bb 2>:
cilsimp.4_1 = p;
cilsimp.3_3 = (long long int *) cilsimp.4_1;
cilsimp.1_4 = *cilsimp.3_3;
cilsimp.1_5 = cilsimp.1_4 & -4096;
cilsimp.1_6 = cilsimp.1_5 | 1;
*cilsimp.3_3 = cilsimp.1_6;
cilsimp.7_8 = (long long int *) &s;
cilsimp.5_9 = *cilsimp.7_8;
cilsimp.5_10 = cilsimp.5_9 & -4096;
cilsimp.5_11 = cilsimp.5_10;
*cilsimp.7_8 = cilsimp.5_11;
cilsimp.11_13 = cilsimp.7_8;
cilsimp.9_14 = cilsimp.5_10;
cilsimp.9_15 = cilsimp.9_14 & -16773121;
cilsimp.9_16 = cilsimp.9_15;
*cilsimp.11_13 = cilsimp.9_16;
cilsimp.15_17 = cilsimp.4_1;
cilsimp.14_19 = cilsimp.3_3;
cilsimp.13_20 = cilsimp.1_6;
cilsimp.13_21 = cilsimp.13_20 << 52;
cilsimp.13_22 = cilsimp.13_21 >> 52;
D.1516_23 = (<unnamed-signed:12>) cilsimp.13_22;
D.1517_24 = (int) D.1516_23;
cilsimp.17_26 = cilsimp.7_8;looking at the other passes didn't provide
cilsimp.16_27 = cilsimp.9_15;
cilsimp.16_28 = cilsimp.16_27 << 40;
cilsimp.16_29 = cilsimp.16_28 >> 52;
D.1518_30 = (<unnamed-signed:12>) cilsimp.16_29;
D.1519_31 = (int) D.1518_30;
D.1515_32 = D.1517_24 + D.1519_31;
return D.1515_32;
}
The problem is that FRE optimizes away the explicit load used for getting the
value of p->a and replaces it with the constant value assigned in the first line
of main (1). This is wrong because the assignment s.a = 0 overwrites p->a
however it seems that FRE doesn't realize that the pointers simpcil.3 and
simpcil.7 are aliases and that the assignment *cilsimp.7 = cilsimp.5; overwrites
the value of p->a with 0.
I believe I must be doing something horribly wrong which breaks alias
analysis. and I'm not sure when this is information is built in the first place
and how to keep it up to date with the transformed code.
Sorry for the long post but I'm really stuck and even looking at the other
passes and internal documentation didn't provide much clues about how to deal
with this problem.
Gabriele Svelto