Commit 30bc5d7b authored by Russ Cox's avatar Russ Cox

cmd/8c: fix store to complex uint64 ptr

Assignment of a computed uint64 value to an
address derived with a function call was executing
the call after computing the value, which trashed
the value (held in registers).

long long *f(void) { return 0; }
void g(int x, int y) {
        *f() = (long long)x | (long long)y<<32;
}

Before:

(x.c:3)	TEXT	g+0(SB),(gok(71))
...
(x.c:4)	ORL	AX,DX
(x.c:4)	ORL	CX,BX
(x.c:4)	CALL	,f+0(SB)
(x.c:4)	MOVL	DX,(AX)
(x.c:4)	MOVL	BX,4(AX)

After:
(x.c:3)	TEXT	g+0(SB),(gok(71))
(x.c:4)	CALL	,f+0(SB)
...
(x.c:4)	ORL	CX,BX
(x.c:4)	ORL	DX,BP
(x.c:4)	MOVL	BX,(AX)
(x.c:4)	MOVL	BP,4(AX)

Fixes #3501.

R=ken2
CC=golang-dev
https://golang.org/cl/5998043
parent ae382129
......@@ -1601,6 +1601,33 @@ cgen64(Node *n, Node *nn)
prtree(n, "cgen64");
print("AX = %d\n", reg[D_AX]);
}
if(nn != Z && nn->complex >= FNX) {
// Evaluate nn address to register
// before we use registers for n.
// Otherwise the call during computation of nn
// will smash the registers. See
// http://golang.org/issue/3501.
// If both n and nn want calls, refuse to compile.
if(n != Z && n->complex >= FNX)
diag(n, "cgen64 miscompile");
reglcgen(&nod1, nn, Z);
m = cgen64(n, &nod1);
regfree(&nod1);
if(m == 0) {
// Now what? We computed &nn, which involved a
// function call, and didn't use it. The caller will recompute nn,
// calling the function a second time.
// We can figure out what to do later, if this actually happens.
diag(n, "cgen64 miscompile");
}
return m;
}
cmp = 0;
sh = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment