This code segfaults.
=====================
void bug8095(int z, ref int p1, ref int p2, int xxx, ref int p4, ref int p5)
{
int x = z / 3;
void inner() {
p4 = 1;
int c = 0;
if (x == 4)
c = 1;
p1 = c;
x = c;
}
if( z >= 0) {
x = z / 5;
inner();
}
p5 = 0;
p2 = 0;
}
void main()
{
int x1, x2, x4, x5;
bug8095(0, x1, x2, 0, x4, x5);
}
Comment #1 by clugdbug — 2012-05-15T04:14:08Z
'Reduced' test case doesn't require -inline. This is a pure optimizer bug.
It requires a nested function, but the nested function isn't actually used.
void bug8095(int z, ref int p1, ref int p2, int xxx, ref int p4, ref int p5)
{
int x = z / 3;
void never_used()
{
p4 = 0;
int unused = 0;
if (x == 4) unused = 1;
}
if (z >= 0) {
p1 = 0;
p4 = 0;
p5 = 0;
int c = 0;
if ( z / 5 )
c = 1;
p2 = c;
x = c;
}
}
void main()
{
int x1, x2, x4, x5;
bug8095(0, x1, x2, 0, x4, x5);
}
Comment #2 by k.hara.pg — 2012-05-15T04:41:04Z
This is similar to bug 8093.
It occurs in Windows 7 64-bit, and the cause is accessing ref variable in outer scope from nested function.
int g;
ref int foo() {
ref int __result;
Container c;
switch(c.opApply((ref int n){
__result = g; // accessing ref variable from nested function
return 2;
return 0;
})){
default: break;
case 2: return __vresult;
}
return g;
}
Comment #3 by clugdbug — 2012-05-15T07:18:48Z
In the example code in comment 1, both z and p4 get assigned to the same register (ESI). Then assigning p4 = 0 sets *z = 0, hence the segfault.
This bug disappears when you comment out the call to deadvar() in optfunc(), go.c; then it doesn't think it can reuse the register. Also, if the function is made simpler, then there are still available registers, so it doesn't try to reuse it.
Bug 8093 isn't an optimizer bug, so I suspect it's unrelated. But I guess its possible that there is a root cause early on which is common to both bugs -- I haven't yet worked out why this one is happening.
Comment #4 by clugdbug — 2012-05-16T01:43:57Z
A little further reduced. Doesn't need ref. The complicated thing about this test case is the third parameter, which goes into EDX. The two divisions, one in each section, prevent any variable from being stored in RDX. Probably there is some simpler way of forcing it to run out of registers.
Compiling with --r gives the message:
symbol 'z' spilled in reg R9
and this is where the problem happens.
edx must be the third last parameter, since RDX is used in the division. All the other parameters (and hence registers) can be shuffled around.
---------------------------
void bug8095(int p0, int *p1, int z, int edx, int *p4, int p5)
{
int x = z / 3;
if (z) {
int c = p5 + *p1 + p0; // *p1 segfaults -- it does *z !!
if ( z / 5 )
c = 1;
*p4 = c;
x = c;
}
void never_used() {
++x;
int * unused = p1; // kills p4 somehow
}
}
void main() {
int x, y;
bug8095(0, &x, 1, 0, &y, 0);
}
Comment #5 by clugdbug — 2012-05-16T08:34:18Z
As far as I can tell, the problem is with spilling registers.
When a spill occurs ( creg_map(), called from cgreg_assign() line cgreg.c:925)
I don't see how it marks the fastpar register as not being valid anymore.
Then in cod1.c, loaddata(), line 3818, it decides that "we can use register that parameter was passed in".
So it doesn't bother to reload it.
Not sure how to fix this.
Comment #6 by github-bugzilla — 2012-05-16T16:13:57Z