compiler: fix "fragment covers entire variable" bug
This bug could sometimes be triggered by syscall/js code it seems. But it's a generic bug, not specific to WebAssembly.
Этот коммит содержится в:
родитель
4be9802d26
коммит
b44d41d9ec
6 изменённых файлов: 45 добавлений и 16 удалений
|
@ -58,10 +58,10 @@ func (b *builder) createCall(fn llvm.Value, args []llvm.Value, name string) llvm
|
|||
|
||||
// Expand an argument type to a list that can be used in a function call
|
||||
// parameter list.
|
||||
func expandFormalParamType(t llvm.Type, name string, goType types.Type) []paramInfo {
|
||||
func (c *compilerContext) expandFormalParamType(t llvm.Type, name string, goType types.Type) []paramInfo {
|
||||
switch t.TypeKind() {
|
||||
case llvm.StructTypeKind:
|
||||
fieldInfos := flattenAggregateType(t, name, goType)
|
||||
fieldInfos := c.flattenAggregateType(t, name, goType)
|
||||
if len(fieldInfos) <= maxFieldsPerParam {
|
||||
return fieldInfos
|
||||
} else {
|
||||
|
@ -105,7 +105,7 @@ func (b *builder) expandFormalParamOffsets(t llvm.Type) []uint64 {
|
|||
func (b *builder) expandFormalParam(v llvm.Value) []llvm.Value {
|
||||
switch v.Type().TypeKind() {
|
||||
case llvm.StructTypeKind:
|
||||
fieldInfos := flattenAggregateType(v.Type(), "", nil)
|
||||
fieldInfos := b.flattenAggregateType(v.Type(), "", nil)
|
||||
if len(fieldInfos) <= maxFieldsPerParam {
|
||||
fields := b.flattenAggregate(v)
|
||||
if len(fields) != len(fieldInfos) {
|
||||
|
@ -124,12 +124,15 @@ func (b *builder) expandFormalParam(v llvm.Value) []llvm.Value {
|
|||
|
||||
// Try to flatten a struct type to a list of types. Returns a 1-element slice
|
||||
// with the passed in type if this is not possible.
|
||||
func flattenAggregateType(t llvm.Type, name string, goType types.Type) []paramInfo {
|
||||
func (c *compilerContext) flattenAggregateType(t llvm.Type, name string, goType types.Type) []paramInfo {
|
||||
typeFlags := getTypeFlags(goType)
|
||||
switch t.TypeKind() {
|
||||
case llvm.StructTypeKind:
|
||||
paramInfos := make([]paramInfo, 0, t.StructElementTypesCount())
|
||||
var paramInfos []paramInfo
|
||||
for i, subfield := range t.StructElementTypes() {
|
||||
if c.targetData.TypeAllocSize(subfield) == 0 {
|
||||
continue
|
||||
}
|
||||
suffix := strconv.Itoa(i)
|
||||
if goType != nil {
|
||||
// Try to come up with a good suffix for this struct field,
|
||||
|
@ -152,7 +155,7 @@ func flattenAggregateType(t llvm.Type, name string, goType types.Type) []paramIn
|
|||
suffix = []string{"context", "funcptr"}[i]
|
||||
}
|
||||
}
|
||||
subInfos := flattenAggregateType(subfield, name+"."+suffix, extractSubfield(goType, i))
|
||||
subInfos := c.flattenAggregateType(subfield, name+"."+suffix, extractSubfield(goType, i))
|
||||
for i := range subInfos {
|
||||
subInfos[i].flags |= typeFlags
|
||||
}
|
||||
|
@ -218,8 +221,11 @@ func extractSubfield(t types.Type, field int) types.Type {
|
|||
func (c *compilerContext) flattenAggregateTypeOffsets(t llvm.Type) []uint64 {
|
||||
switch t.TypeKind() {
|
||||
case llvm.StructTypeKind:
|
||||
fields := make([]uint64, 0, t.StructElementTypesCount())
|
||||
var fields []uint64
|
||||
for fieldIndex, field := range t.StructElementTypes() {
|
||||
if c.targetData.TypeAllocSize(field) == 0 {
|
||||
continue
|
||||
}
|
||||
suboffsets := c.flattenAggregateTypeOffsets(field)
|
||||
offset := c.targetData.ElementOffset(t, fieldIndex)
|
||||
for i := range suboffsets {
|
||||
|
@ -238,8 +244,11 @@ func (c *compilerContext) flattenAggregateTypeOffsets(t llvm.Type) []uint64 {
|
|||
func (b *builder) flattenAggregate(v llvm.Value) []llvm.Value {
|
||||
switch v.Type().TypeKind() {
|
||||
case llvm.StructTypeKind:
|
||||
fields := make([]llvm.Value, 0, v.Type().StructElementTypesCount())
|
||||
for i := range v.Type().StructElementTypes() {
|
||||
var fields []llvm.Value
|
||||
for i, field := range v.Type().StructElementTypes() {
|
||||
if b.targetData.TypeAllocSize(field) == 0 {
|
||||
continue
|
||||
}
|
||||
subfield := b.CreateExtractValue(v, i, "")
|
||||
subfields := b.flattenAggregate(subfield)
|
||||
fields = append(fields, subfields...)
|
||||
|
@ -266,10 +275,13 @@ func (b *builder) collapseFormalParam(t llvm.Type, fields []llvm.Value) llvm.Val
|
|||
func (b *builder) collapseFormalParamInternal(t llvm.Type, fields []llvm.Value) (llvm.Value, []llvm.Value) {
|
||||
switch t.TypeKind() {
|
||||
case llvm.StructTypeKind:
|
||||
flattened := flattenAggregateType(t, "", nil)
|
||||
flattened := b.flattenAggregateType(t, "", nil)
|
||||
if len(flattened) <= maxFieldsPerParam {
|
||||
value := llvm.ConstNull(t)
|
||||
for i, subtyp := range t.StructElementTypes() {
|
||||
if b.targetData.TypeAllocSize(subtyp) == 0 {
|
||||
continue
|
||||
}
|
||||
structField, remaining := b.collapseFormalParamInternal(subtyp, fields)
|
||||
fields = remaining
|
||||
value = b.CreateInsertValue(value, structField, i, "")
|
||||
|
|
|
@ -23,7 +23,7 @@ import (
|
|||
// Version of the compiler pacakge. Must be incremented each time the compiler
|
||||
// package changes in a way that affects the generated LLVM module.
|
||||
// This version is independent of the TinyGo version number.
|
||||
const Version = 5 // last change: add method set to interface types
|
||||
const Version = 6 // last change: fix issue 1304
|
||||
|
||||
func init() {
|
||||
llvm.InitializeAllTargets()
|
||||
|
@ -829,7 +829,7 @@ func (b *builder) createFunction() {
|
|||
for _, param := range b.fn.Params {
|
||||
llvmType := b.getLLVMType(param.Type())
|
||||
fields := make([]llvm.Value, 0, 1)
|
||||
for _, info := range expandFormalParamType(llvmType, param.Name(), param.Type()) {
|
||||
for _, info := range b.expandFormalParamType(llvmType, param.Name(), param.Type()) {
|
||||
param := b.llvmFn.Param(llvmParamIndex)
|
||||
param.SetName(info.name)
|
||||
fields = append(fields, param)
|
||||
|
|
|
@ -124,13 +124,13 @@ func (c *compilerContext) getRawFuncType(typ *types.Signature) llvm.Type {
|
|||
// The receiver is not an interface, but a i8* type.
|
||||
recv = c.i8ptrType
|
||||
}
|
||||
for _, info := range expandFormalParamType(recv, "", nil) {
|
||||
for _, info := range c.expandFormalParamType(recv, "", nil) {
|
||||
paramTypes = append(paramTypes, info.llvmType)
|
||||
}
|
||||
}
|
||||
for i := 0; i < typ.Params().Len(); i++ {
|
||||
subType := c.getLLVMType(typ.Params().At(i).Type())
|
||||
for _, info := range expandFormalParamType(subType, "", nil) {
|
||||
for _, info := range c.expandFormalParamType(subType, "", nil) {
|
||||
paramTypes = append(paramTypes, info.llvmType)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -456,7 +456,7 @@ func (c *compilerContext) getInterfaceInvokeWrapper(fn *ssa.Function, llvmFn llv
|
|||
// Get the expanded receiver type.
|
||||
receiverType := c.getLLVMType(fn.Signature.Recv().Type())
|
||||
var expandedReceiverType []llvm.Type
|
||||
for _, info := range expandFormalParamType(receiverType, "", nil) {
|
||||
for _, info := range c.expandFormalParamType(receiverType, "", nil) {
|
||||
expandedReceiverType = append(expandedReceiverType, info.llvmType)
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ func (c *compilerContext) getFunction(fn *ssa.Function) llvm.Value {
|
|||
var paramInfos []paramInfo
|
||||
for _, param := range getParams(fn.Signature) {
|
||||
paramType := c.getLLVMType(param.Type())
|
||||
paramFragmentInfos := expandFormalParamType(paramType, param.Name(), param.Type())
|
||||
paramFragmentInfos := c.expandFormalParamType(paramType, param.Name(), param.Type())
|
||||
paramInfos = append(paramInfos, paramFragmentInfos...)
|
||||
}
|
||||
|
||||
|
|
17
testdata/calls.go
предоставленный
17
testdata/calls.go
предоставленный
|
@ -74,6 +74,14 @@ func main() {
|
|||
//Test deferred builtins
|
||||
testDeferBuiltinClose()
|
||||
testDeferBuiltinDelete()
|
||||
|
||||
// Check for issue 1304.
|
||||
// There are two fields in this struct, one of which is zero-length so the
|
||||
// other covers the entire struct. This led to a verification error for
|
||||
// debug info, which used DW_OP_LLVM_fragment for a field that practically
|
||||
// covered the entire variable.
|
||||
var x issue1304
|
||||
x.call()
|
||||
}
|
||||
|
||||
func runFunc(f func(int), arg int) {
|
||||
|
@ -211,3 +219,12 @@ func foo(bar *Bar) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
type issue1304 struct {
|
||||
a [0]int // zero-length field
|
||||
b int // field 'b' covers entire struct
|
||||
}
|
||||
|
||||
func (x issue1304) call() {
|
||||
// nothing to do
|
||||
}
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче