diff --git a/src/cmd/compile/internal/amd64/ggen.go b/src/cmd/compile/internal/amd64/ggen.go index 0cd3473e29..84c3d5d7d4 100644 --- a/src/cmd/compile/internal/amd64/ggen.go +++ b/src/cmd/compile/internal/amd64/ggen.go @@ -365,24 +365,25 @@ func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) { gc.Cgenr(nl, &n1, res) var n2 gc.Node gc.Cgenr(nr, &n2, nil) - var ax gc.Node - gc.Nodreg(&ax, t, x86.REG_AX) + var ax, oldax, dx, olddx gc.Node + savex(x86.REG_AX, &ax, &oldax, res, gc.Types[gc.TUINT64]) + savex(x86.REG_DX, &dx, &olddx, res, gc.Types[gc.TUINT64]) gmove(&n1, &ax) gins(a, &n2, nil) gc.Regfree(&n2) gc.Regfree(&n1) - var dx gc.Node if t.Width == 1 { // byte multiply behaves differently. - gc.Nodreg(&ax, t, x86.REG_AH) - - gc.Nodreg(&dx, t, x86.REG_DX) - gmove(&ax, &dx) + var byteAH, byteDX gc.Node + gc.Nodreg(&byteAH, t, x86.REG_AH) + gc.Nodreg(&byteDX, t, x86.REG_DX) + gmove(&byteAH, &byteDX) } - - gc.Nodreg(&dx, t, x86.REG_DX) gmove(&dx, res) + + restx(&ax, &oldax) + restx(&dx, &olddx) } /* diff --git a/src/cmd/compile/internal/x86/ggen.go b/src/cmd/compile/internal/x86/ggen.go index 4e72dcb1e9..e559a9f5da 100644 --- a/src/cmd/compile/internal/x86/ggen.go +++ b/src/cmd/compile/internal/x86/ggen.go @@ -531,24 +531,21 @@ func cgen_bmul(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) bool { func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) { var n1 gc.Node var n2 gc.Node - var ax gc.Node - var dx gc.Node t := nl.Type a := optoas(gc.OHMUL, t) // gen nl in n1. gc.Tempname(&n1, t) - gc.Cgen(nl, &n1) // gen nr in n2. gc.Regalloc(&n2, t, res) - gc.Cgen(nr, &n2) - // multiply. - gc.Nodreg(&ax, t, x86.REG_AX) + var ax, oldax, dx, olddx gc.Node + savex(x86.REG_AX, &ax, &oldax, res, gc.Types[gc.TUINT32]) + savex(x86.REG_DX, &dx, &olddx, res, gc.Types[gc.TUINT32]) gmove(&n2, &ax) gins(a, &n1, nil) @@ -556,14 +553,16 @@ func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) { if t.Width == 1 { // byte multiply behaves differently. - gc.Nodreg(&ax, t, x86.REG_AH) - - gc.Nodreg(&dx, t, x86.REG_DX) - gmove(&ax, &dx) + var byteAH, byteDX gc.Node + gc.Nodreg(&byteAH, t, x86.REG_AH) + gc.Nodreg(&byteDX, t, x86.REG_DX) + gmove(&byteAH, &byteDX) } - gc.Nodreg(&dx, t, x86.REG_DX) gmove(&dx, res) + + restx(&ax, &oldax) + restx(&dx, &olddx) } /* diff --git a/test/fixedbugs/issue12411.go b/test/fixedbugs/issue12411.go new file mode 100644 index 0000000000..0a8b7c362b --- /dev/null +++ b/test/fixedbugs/issue12411.go @@ -0,0 +1,24 @@ +// +build !386 +// run + +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 12411. Loss of AX during %. + +package main + +func main() { + x := f(4) + if x != 0 { + println("BUG: x=", x) + } +} + +//go:noinline +func f(x int) int { + // AX was live on entry to one of the % code generations, + // and the % code generation smashed it. + return ((2 * x) % 3) % (2 % ((x << 2) ^ (x % 3))) +}