From: Todd Neal Date: Fri, 19 Feb 2016 22:58:21 +0000 (-0600) Subject: [dev.ssa] cmd/compile: truncate auxint when constructing Prog X-Git-Tag: go1.7beta1~1623^2^2~30 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=c17b6b488cbf448da374d576be0f921e655b00b1;p=gostls13.git [dev.ssa] cmd/compile: truncate auxint when constructing Prog The upper bits of 8/16/32 bit constants are undefined. We need to truncate in order to prevent x86.oclass misidentifying the size of the constant. Fixes #14389 Change-Id: I3e5ff79cd904376572a93f489ba7e152a5cb6e60 Reviewed-on: https://go-review.googlesource.com/19740 Reviewed-by: Keith Randall --- diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 3f8fdce83b..19fda373bf 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -3990,7 +3990,7 @@ func (s *genState) genValue(v *ssa.Value) { r := regnum(v) a := regnum(v.Args[0]) if r == a { - if v.AuxInt == 1 { + if v.AuxInt2Int64() == 1 { var asm int switch v.Op { // Software optimization manual recommends add $1,reg. @@ -4009,7 +4009,7 @@ func (s *genState) genValue(v *ssa.Value) { p.To.Type = obj.TYPE_REG p.To.Reg = r return - } else if v.AuxInt == -1 { + } else if v.AuxInt2Int64() == -1 { var asm int switch v.Op { case ssa.OpAMD64ADDQconst: @@ -4026,7 +4026,7 @@ func (s *genState) genValue(v *ssa.Value) { } else { p := Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST - p.From.Offset = v.AuxInt + p.From.Offset = v.AuxInt2Int64() p.To.Type = obj.TYPE_REG p.To.Reg = r return @@ -4044,7 +4044,7 @@ func (s *genState) genValue(v *ssa.Value) { p := Prog(asm) p.From.Type = obj.TYPE_MEM p.From.Reg = a - p.From.Offset = v.AuxInt + p.From.Offset = v.AuxInt2Int64() p.To.Type = obj.TYPE_REG p.To.Reg = r case ssa.OpAMD64MULQconst, ssa.OpAMD64MULLconst, ssa.OpAMD64MULWconst, ssa.OpAMD64MULBconst: @@ -4059,7 +4059,7 @@ func (s *genState) genValue(v *ssa.Value) { } p := Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST - p.From.Offset = v.AuxInt + p.From.Offset = v.AuxInt2Int64() p.To.Type = obj.TYPE_REG p.To.Reg = r // TODO: Teach doasm to compile the three-address multiply imul $c, r1, r2 @@ -4074,7 +4074,7 @@ func (s *genState) genValue(v *ssa.Value) { // a = b + (- const), saves us 1 instruction. We can't fit // - (-1 << 31) into 4 bytes offset in lea. // We handle 2-address just fine below. - if v.AuxInt == -1<<31 || x == r { + if v.AuxInt2Int64() == -1<<31 || x == r { if x != r { // This code compensates for the fact that the register allocator // doesn't understand 2-address instructions yet. TODO: fix that. @@ -4086,10 +4086,10 @@ func (s *genState) genValue(v *ssa.Value) { } p := Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST - p.From.Offset = v.AuxInt + p.From.Offset = v.AuxInt2Int64() p.To.Type = obj.TYPE_REG p.To.Reg = r - } else if x == r && v.AuxInt == -1 { + } else if x == r && v.AuxInt2Int64() == -1 { var asm int // x = x - (-1) is the same as x++ // See OpAMD64ADDQconst comments about inc vs add $1,reg @@ -4104,7 +4104,7 @@ func (s *genState) genValue(v *ssa.Value) { p := Prog(asm) p.To.Type = obj.TYPE_REG p.To.Reg = r - } else if x == r && v.AuxInt == 1 { + } else if x == r && v.AuxInt2Int64() == 1 { var asm int switch v.Op { case ssa.OpAMD64SUBQconst: @@ -4130,7 +4130,7 @@ func (s *genState) genValue(v *ssa.Value) { p := Prog(asm) p.From.Type = obj.TYPE_MEM p.From.Reg = x - p.From.Offset = -v.AuxInt + p.From.Offset = -v.AuxInt2Int64() p.To.Type = obj.TYPE_REG p.To.Reg = r } @@ -4157,7 +4157,7 @@ func (s *genState) genValue(v *ssa.Value) { } p := Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST - p.From.Offset = v.AuxInt + p.From.Offset = v.AuxInt2Int64() p.To.Type = obj.TYPE_REG p.To.Reg = r case ssa.OpAMD64SBBQcarrymask, ssa.OpAMD64SBBLcarrymask: @@ -4204,29 +4204,18 @@ func (s *genState) genValue(v *ssa.Value) { p.From.Type = obj.TYPE_REG p.From.Reg = regnum(v.Args[0]) p.To.Type = obj.TYPE_CONST - p.To.Offset = v.AuxInt + p.To.Offset = v.AuxInt2Int64() case ssa.OpAMD64TESTQconst, ssa.OpAMD64TESTLconst, ssa.OpAMD64TESTWconst, ssa.OpAMD64TESTBconst: p := Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST - p.From.Offset = v.AuxInt + p.From.Offset = v.AuxInt2Int64() p.To.Type = obj.TYPE_REG p.To.Reg = regnum(v.Args[0]) case ssa.OpAMD64MOVBconst, ssa.OpAMD64MOVWconst, ssa.OpAMD64MOVLconst, ssa.OpAMD64MOVQconst: x := regnum(v) p := Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST - var i int64 - switch v.Op { - case ssa.OpAMD64MOVBconst: - i = int64(v.AuxInt8()) - case ssa.OpAMD64MOVWconst: - i = int64(v.AuxInt16()) - case ssa.OpAMD64MOVLconst: - i = int64(v.AuxInt32()) - case ssa.OpAMD64MOVQconst: - i = v.AuxInt - } - p.From.Offset = i + p.From.Offset = v.AuxInt2Int64() p.To.Type = obj.TYPE_REG p.To.Reg = x // If flags are live at this instruction, suppress the diff --git a/src/cmd/compile/internal/gc/testdata/arith_ssa.go b/src/cmd/compile/internal/gc/testdata/arith_ssa.go index 821c0dd12d..f4bea0ed11 100644 --- a/src/cmd/compile/internal/gc/testdata/arith_ssa.go +++ b/src/cmd/compile/internal/gc/testdata/arith_ssa.go @@ -10,6 +10,42 @@ package main import "fmt" +const ( + y = 0x0fffFFFF +) + +//go:noinline +func invalidAdd_ssa(x uint32) uint32 { + return x + y + y + y + y + y + y + y + y + y + y + y + y + y + y + y + y + y +} + +//go:noinline +func invalidSub_ssa(x uint32) uint32 { + return x - y - y - y - y - y - y - y - y - y - y - y - y - y - y - y - y - y +} + +//go:noinline +func invalidMul_ssa(x uint32) uint32 { + return x * y * y * y * y * y * y * y * y * y * y * y * y * y * y * y * y * y +} + +// testLargeConst tests a situation where larger than 32 bit consts were passed to ADDL +// causing an invalid instruction error. +func testLargeConst() { + if want, got := uint32(268435440), invalidAdd_ssa(1); want != got { + println("testLargeConst add failed, wanted", want, "got", got) + failed = true + } + if want, got := uint32(4026531858), invalidSub_ssa(1); want != got { + println("testLargeConst sub failed, wanted", want, "got", got) + failed = true + } + if want, got := uint32(268435455), invalidMul_ssa(1); want != got { + println("testLargeConst mul failed, wanted", want, "got", got) + failed = true + } +} + // testArithRshConst ensures that "const >> const" right shifts correctly perform // sign extension on the lhs constant func testArithRshConst() { @@ -394,6 +430,7 @@ func main() { testOverflowConstShift() testArithConstShift() testArithRshConst() + testLargeConst() if failed { panic("failed") diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go index c2ea6ee202..cc8c9fe871 100644 --- a/src/cmd/compile/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go @@ -77,6 +77,25 @@ func (v *Value) AuxInt32() int32 { } return int32(v.AuxInt) } + +// AuxInt2Int64 is used to sign extend the lower bits of AuxInt according to +// the size of AuxInt specified in the opcode table. +func (v *Value) AuxInt2Int64() int64 { + switch opcodeTable[v.Op].auxType { + case auxInt64: + return v.AuxInt + case auxInt32: + return int64(int32(v.AuxInt)) + case auxInt16: + return int64(int16(v.AuxInt)) + case auxInt8: + return int64(int8(v.AuxInt)) + default: + v.Fatalf("op %s doesn't have an aux int field", v.Op) + return -1 + } +} + func (v *Value) AuxFloat() float64 { if opcodeTable[v.Op].auxType != auxFloat { v.Fatalf("op %s doesn't have a float aux field", v.Op)