mirror of
https://github.com/golang/go.git
synced 2025-05-28 19:02:22 +00:00
[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 <khr@golang.org>
This commit is contained in:
parent
9dc1334cc7
commit
c17b6b488c
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user