From 30bc5d7bbd8644e044c8c3ecfceca9455326b7a5 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 10 Apr 2012 10:45:58 -0400 Subject: [PATCH] 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 --- src/cmd/8c/cgen64.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/cmd/8c/cgen64.c b/src/cmd/8c/cgen64.c index 3424f762c5..21619b8930 100644 --- a/src/cmd/8c/cgen64.c +++ b/src/cmd/8c/cgen64.c @@ -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; -- 2.48.1