mirror of
https://github.com/golang/go
synced 2024-10-05 18:31:28 -06:00
[dev.ssa] cmd/compile: fix failed lowerings
One was OAPPEND of large types. We need to mem-mem copy them instead of storing them. Another was pointer-like struct and array types being put in the data field of an eface. We need to use the underlying pointer type for the load that fills in the eface.data field. Change-Id: Id8278c0381904e52d59011a66ce46386b41b5521 Reviewed-on: https://go-review.googlesource.com/15552 Run-TryBot: Keith Randall <khr@golang.org> Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
9aba7e76f6
commit
808d7c70d5
@ -1801,6 +1801,31 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||
case OEFACE:
|
||||
tab := s.expr(n.Left)
|
||||
data := s.expr(n.Right)
|
||||
// The frontend allows putting things like struct{*byte} in
|
||||
// the data portion of an eface. But we don't want struct{*byte}
|
||||
// as a register type because (among other reasons) the liveness
|
||||
// analysis is confused by the "fat" variables that result from
|
||||
// such types being spilled.
|
||||
// So here we ensure that we are selecting the underlying pointer
|
||||
// when we build an eface.
|
||||
for !data.Type.IsPtr() {
|
||||
switch {
|
||||
case data.Type.IsArray():
|
||||
data = s.newValue2(ssa.OpArrayIndex, data.Type.Elem(), data, s.constInt(Types[TINT], 0))
|
||||
case data.Type.IsStruct():
|
||||
for i := data.Type.NumFields() - 1; i >= 0; i-- {
|
||||
f := data.Type.FieldType(i)
|
||||
if f.Size() == 0 {
|
||||
// eface type could also be struct{p *byte; q [0]int}
|
||||
continue
|
||||
}
|
||||
data = s.newValue1I(ssa.OpStructSelect, f, data.Type.FieldOff(i), data)
|
||||
break
|
||||
}
|
||||
default:
|
||||
s.Fatalf("type being put into an eface isn't a pointer")
|
||||
}
|
||||
}
|
||||
return s.newValue2(ssa.OpIMake, n.Type, tab, data)
|
||||
|
||||
case OSLICE, OSLICEARR:
|
||||
@ -1898,8 +1923,15 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||
|
||||
// Evaluate args
|
||||
args := make([]*ssa.Value, 0, nargs)
|
||||
store := make([]bool, 0, nargs)
|
||||
for l := n.List.Next; l != nil; l = l.Next {
|
||||
if canSSAType(l.N.Type) {
|
||||
args = append(args, s.expr(l.N))
|
||||
store = append(store, true)
|
||||
} else {
|
||||
args = append(args, s.addr(l.N))
|
||||
store = append(store, false)
|
||||
}
|
||||
}
|
||||
|
||||
p = s.variable(&ptrVar, pt) // generates phi for ptr
|
||||
@ -1907,7 +1939,11 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||
p2 := s.newValue2(ssa.OpPtrIndex, pt, p, l)
|
||||
for i, arg := range args {
|
||||
addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(Types[TUINTPTR], int64(i)))
|
||||
if store[i] {
|
||||
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg, s.mem())
|
||||
} else {
|
||||
s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, et.Size(), addr, arg, s.mem())
|
||||
}
|
||||
if haspointers(et) {
|
||||
// TODO: just one write barrier call for all of these writes?
|
||||
// TODO: maybe just one writeBarrierEnabled check?
|
||||
|
@ -88,6 +88,10 @@ func (t *Type) IsArray() bool {
|
||||
return t.Etype == TARRAY && t.Bound >= 0
|
||||
}
|
||||
|
||||
func (t *Type) IsStruct() bool {
|
||||
return t.Etype == TSTRUCT
|
||||
}
|
||||
|
||||
func (t *Type) IsInterface() bool {
|
||||
return t.Etype == TINTER
|
||||
}
|
||||
@ -99,5 +103,42 @@ func (t *Type) PtrTo() ssa.Type {
|
||||
return Ptrto(t)
|
||||
}
|
||||
|
||||
func (t *Type) NumFields() int64 {
|
||||
return int64(countfield(t))
|
||||
}
|
||||
func (t *Type) FieldType(i int64) ssa.Type {
|
||||
// TODO: store fields in a slice so we can
|
||||
// look them up by index in constant time.
|
||||
for t1 := t.Type; t1 != nil; t1 = t1.Down {
|
||||
if t1.Etype != TFIELD {
|
||||
panic("non-TFIELD in a TSTRUCT")
|
||||
}
|
||||
if i == 0 {
|
||||
return t1.Type
|
||||
}
|
||||
i--
|
||||
}
|
||||
panic("not enough fields")
|
||||
}
|
||||
func (t *Type) FieldOff(i int64) int64 {
|
||||
for t1 := t.Type; t1 != nil; t1 = t1.Down {
|
||||
if t1.Etype != TFIELD {
|
||||
panic("non-TFIELD in a TSTRUCT")
|
||||
}
|
||||
if i == 0 {
|
||||
return t1.Width
|
||||
}
|
||||
i--
|
||||
}
|
||||
panic("not enough fields")
|
||||
}
|
||||
|
||||
func (t *Type) NumElem() int64 {
|
||||
if t.Etype != TARRAY {
|
||||
panic("NumElem on non-TARRAY")
|
||||
}
|
||||
return int64(t.Bound)
|
||||
}
|
||||
|
||||
func (t *Type) IsMemory() bool { return false }
|
||||
func (t *Type) IsFlags() bool { return false }
|
||||
|
@ -21,14 +21,21 @@ type Type interface {
|
||||
IsString() bool
|
||||
IsSlice() bool
|
||||
IsArray() bool
|
||||
IsStruct() bool
|
||||
IsInterface() bool
|
||||
|
||||
IsMemory() bool // special ssa-package-only types
|
||||
IsFlags() bool
|
||||
|
||||
Elem() Type // given []T or *T, return T
|
||||
Elem() Type // given []T or *T or [n]T, return T
|
||||
PtrTo() Type // given T, return *T
|
||||
|
||||
NumFields() int64 // # of fields of a struct
|
||||
FieldType(i int64) Type // type of ith field of the struct
|
||||
FieldOff(i int64) int64 // offset of ith field of the struct
|
||||
|
||||
NumElem() int64 // # of elements of an array
|
||||
|
||||
String() string
|
||||
SimpleString() string // a coarser generic description of T, e.g. T's underlying type
|
||||
Equal(Type) bool
|
||||
@ -52,6 +59,7 @@ func (t *CompilerType) IsPtr() bool { return false }
|
||||
func (t *CompilerType) IsString() bool { return false }
|
||||
func (t *CompilerType) IsSlice() bool { return false }
|
||||
func (t *CompilerType) IsArray() bool { return false }
|
||||
func (t *CompilerType) IsStruct() bool { return false }
|
||||
func (t *CompilerType) IsInterface() bool { return false }
|
||||
func (t *CompilerType) IsMemory() bool { return t.Memory }
|
||||
func (t *CompilerType) IsFlags() bool { return t.Flags }
|
||||
@ -59,6 +67,10 @@ func (t *CompilerType) String() string { return t.Name }
|
||||
func (t *CompilerType) SimpleString() string { return t.Name }
|
||||
func (t *CompilerType) Elem() Type { panic("not implemented") }
|
||||
func (t *CompilerType) PtrTo() Type { panic("not implemented") }
|
||||
func (t *CompilerType) NumFields() int64 { panic("not implemented") }
|
||||
func (t *CompilerType) FieldType(i int64) Type { panic("not implemented") }
|
||||
func (t *CompilerType) FieldOff(i int64) int64 { panic("not implemented") }
|
||||
func (t *CompilerType) NumElem() int64 { panic("not implemented") }
|
||||
|
||||
func (t *CompilerType) Equal(u Type) bool {
|
||||
x, ok := u.(*CompilerType)
|
||||
|
@ -17,6 +17,7 @@ type TypeImpl struct {
|
||||
string bool
|
||||
slice bool
|
||||
array bool
|
||||
struct_ bool
|
||||
inter bool
|
||||
Elem_ Type
|
||||
|
||||
@ -34,6 +35,7 @@ func (t *TypeImpl) IsPtr() bool { return t.Ptr }
|
||||
func (t *TypeImpl) IsString() bool { return t.string }
|
||||
func (t *TypeImpl) IsSlice() bool { return t.slice }
|
||||
func (t *TypeImpl) IsArray() bool { return t.array }
|
||||
func (t *TypeImpl) IsStruct() bool { return t.struct_ }
|
||||
func (t *TypeImpl) IsInterface() bool { return t.inter }
|
||||
func (t *TypeImpl) IsMemory() bool { return false }
|
||||
func (t *TypeImpl) IsFlags() bool { return false }
|
||||
@ -41,6 +43,10 @@ func (t *TypeImpl) String() string { return t.Name }
|
||||
func (t *TypeImpl) SimpleString() string { return t.Name }
|
||||
func (t *TypeImpl) Elem() Type { return t.Elem_ }
|
||||
func (t *TypeImpl) PtrTo() Type { panic("not implemented") }
|
||||
func (t *TypeImpl) NumFields() int64 { panic("not implemented") }
|
||||
func (t *TypeImpl) FieldType(i int64) Type { panic("not implemented") }
|
||||
func (t *TypeImpl) FieldOff(i int64) int64 { panic("not implemented") }
|
||||
func (t *TypeImpl) NumElem() int64 { panic("not implemented") }
|
||||
|
||||
func (t *TypeImpl) Equal(u Type) bool {
|
||||
x, ok := u.(*TypeImpl)
|
||||
|
Loading…
Reference in New Issue
Block a user