Bug 3914 – Struct as argument that fits in register has member accessed wrong
Status
RESOLVED
Resolution
FIXED
Severity
critical
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86
OS
Windows
Creation time
2010-03-09T10:54:00Z
Last change time
2014-02-15T02:44:09Z
Keywords
patch, wrong-code
Assigned to
nobody
Creator
aldonunez1
Comments
Comment #0 by aldonunez1 — 2010-03-09T10:54:31Z
Depending on the build options and where in a function the struct parameter is used, referencing one member will actually reference another one.
Given the following program:
import std.stdio;
struct SS
{
char a;
char b;
char c;
char d;
// char e;
}
void A( SS ss1 )
{
C: //writeln( ss1.a, ss1.b, ss1.c, ss1.d );
char temp;
temp = ss1.a;
ss1.a = ss1.d;
ss1.d = temp;
temp = ss1.b;
ss1.b = ss1.c;
ss1.c = temp;
B: //writeln( ss1.a, ss1.b, ss1.c, ss1.d );
temp = ss1.a;
ss1.a = ss1.d;
ss1.d = temp;
temp = ss1.b;
ss1.b = ss1.c;
ss1.c = temp;
A: writeln( ss1.a, ss1.b, ss1.c, ss1.d );
}
void main()
{
SS ss3;
ss3.a = 'A';
ss3.b = 'L';
ss3.c = 'D';
ss3.d = 'O';
A( ss3 );
}
If lines A, B, and C are enabled in the following pattern along with the given build options, you get these results:
(none) -g -rel -rel-O -O -g -O
A ALDO ALDO ALDO ALDA ALDA ALDA
B, A ODLA ODLA ODLA ADLA ADLA ADLA
ALDO ALDO ALDO ALDA ALDA ALDA
C, B, A ALDA ALDO ALDA ALDA ALDA ALDA
ODLA ODLA ODLA ODLA ODLA ODLA
ALDO ALDO ALDO ALDO ALDO ALDO
In particular, notice that field 'd' starts off wrong.
If I uncomment field 'e', or change one of them to an int, the problem goes away.
At C, "ALDO" should be printed.
At B, "ODLA" should be printed.
At A, "ALDO" should be printed.
Comment #1 by clugdbug — 2010-03-11T12:51:37Z
Here's a slightly reduced test case which doesn't require any compiler flags.
Not a regression, fails even on DMD0.165.
It's a problem with variadic function parameters and fastpar arguments.
------------
struct SS {
char a, b, c, d;
}
void show(char[] args...) {
assert(args[0]=='A');
assert(args[1]=='L');
assert(args[2]=='D');
assert(args[3]=='O');
}
void A( SS ss ) {
show( ss.a, ss.b, ss.c, ss.d );
}
void main(){
SS ss3;
ss3.a = 'A';
ss3.b = 'L';
ss3.c = 'D';
ss3.d = 'O';
A( ss3 );
}
Comment #2 by clugdbug — 2010-03-12T05:51:40Z
PATCH: The struct ss is passed in EAX. The backend wants ss.b. It sees that ss.b is already in EAX, so it doesn't reload it into AX. But AX actually contains ss.a.
Solution: Disable the optimisation in cod1.loaddata() if it's a subsequent member of the struct.
Index: cod1.c
===================================================================
--- cod1.c (revision 413)
+++ cod1.c (working copy)
@@ -3453,6 +3453,7 @@
// See if we can use register that parameter was passed in
if (regcon.params && e->EV.sp.Vsym->Sclass == SCfastpar &&
regcon.params & mask[e->EV.sp.Vsym->Spreg] &&
+ !(e->Eoper == OPvar && e->EV.sp.Voffset > 0) && // Must be at the base of that variable
sz <= REGSIZE) // make sure no 'paint' to a larger size happened
{
reg = e->EV.sp.Vsym->Spreg;
=========================
Reduced test case:
=========================
struct Snake {
short a, b;
}
void venom(short dd)
{
assert(dd == 'B');
}
void serpent( Snake ss ) {
venom(ss.b);
}
void main(){
Snake s;
s.a = 'A';
s.b = 'B';
serpent( s );
}