Skip to content

Commit 16c2d84

Browse files
aykevldeadprogram
authored andcommitted
compiler: add parameter names to IR
This makes viewing the IR easier because parameters have readable names. This also makes it easier to write compiler tests (still a work in progress), that work in LLVM 9 and LLVM 10, as LLVM 10 started printing value names for unnamed parameters.
1 parent f00bb63 commit 16c2d84

File tree

4 files changed

+89
-42
lines changed

4 files changed

+89
-42
lines changed

compiler/calls.go

Lines changed: 61 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package compiler
22

33
import (
44
"go/types"
5+
"strconv"
56

67
"tinygo.org/x/go-llvm"
78
)
@@ -13,6 +14,14 @@ import (
1314
// a struct contains more fields, it is passed as a struct without expanding.
1415
const maxFieldsPerParam = 3
1516

17+
// paramInfo contains some information collected about a function parameter,
18+
// useful while declaring or defining a function.
19+
type paramInfo struct {
20+
llvmType llvm.Type
21+
name string // name, possibly with suffixes for e.g. struct fields
22+
flags paramFlags
23+
}
24+
1625
// paramFlags identifies parameter attributes for flags. Most importantly, it
1726
// determines which parameters are dereferenceable_or_null and which aren't.
1827
type paramFlags uint8
@@ -48,19 +57,23 @@ func (b *builder) createCall(fn llvm.Value, args []llvm.Value, name string) llvm
4857

4958
// Expand an argument type to a list that can be used in a function call
5059
// parameter list.
51-
func expandFormalParamType(t llvm.Type, goType types.Type) ([]llvm.Type, []paramFlags) {
60+
func expandFormalParamType(t llvm.Type, name string, goType types.Type) []paramInfo {
5261
switch t.TypeKind() {
5362
case llvm.StructTypeKind:
54-
fields, fieldFlags := flattenAggregateType(t, goType)
55-
if len(fields) <= maxFieldsPerParam {
56-
return fields, fieldFlags
63+
fieldInfos := flattenAggregateType(t, name, goType)
64+
if len(fieldInfos) <= maxFieldsPerParam {
65+
return fieldInfos
5766
} else {
5867
// failed to lower
59-
return []llvm.Type{t}, []paramFlags{getTypeFlags(goType)}
6068
}
61-
default:
62-
// TODO: split small arrays
63-
return []llvm.Type{t}, []paramFlags{getTypeFlags(goType)}
69+
}
70+
// TODO: split small arrays
71+
return []paramInfo{
72+
{
73+
llvmType: t,
74+
name: name,
75+
flags: getTypeFlags(goType),
76+
},
6477
}
6578
}
6679

@@ -91,10 +104,10 @@ func (b *builder) expandFormalParamOffsets(t llvm.Type) []uint64 {
91104
func (b *builder) expandFormalParam(v llvm.Value) []llvm.Value {
92105
switch v.Type().TypeKind() {
93106
case llvm.StructTypeKind:
94-
fieldTypes, _ := flattenAggregateType(v.Type(), nil)
95-
if len(fieldTypes) <= maxFieldsPerParam {
107+
fieldInfos := flattenAggregateType(v.Type(), "", nil)
108+
if len(fieldInfos) <= maxFieldsPerParam {
96109
fields := b.flattenAggregate(v)
97-
if len(fields) != len(fieldTypes) {
110+
if len(fields) != len(fieldInfos) {
98111
panic("type and value param lowering don't match")
99112
}
100113
return fields
@@ -110,23 +123,49 @@ func (b *builder) expandFormalParam(v llvm.Value) []llvm.Value {
110123

111124
// Try to flatten a struct type to a list of types. Returns a 1-element slice
112125
// with the passed in type if this is not possible.
113-
func flattenAggregateType(t llvm.Type, goType types.Type) ([]llvm.Type, []paramFlags) {
126+
func flattenAggregateType(t llvm.Type, name string, goType types.Type) []paramInfo {
114127
typeFlags := getTypeFlags(goType)
115128
switch t.TypeKind() {
116129
case llvm.StructTypeKind:
117-
fields := make([]llvm.Type, 0, t.StructElementTypesCount())
118-
fieldFlags := make([]paramFlags, 0, cap(fields))
130+
paramInfos := make([]paramInfo, 0, t.StructElementTypesCount())
119131
for i, subfield := range t.StructElementTypes() {
120-
subfields, subfieldFlags := flattenAggregateType(subfield, extractSubfield(goType, i))
121-
for i := range subfieldFlags {
122-
subfieldFlags[i] |= typeFlags
132+
suffix := strconv.Itoa(i)
133+
if goType != nil {
134+
// Try to come up with a good suffix for this struct field,
135+
// depending on which Go type it's based on.
136+
switch goType := goType.Underlying().(type) {
137+
case *types.Interface:
138+
suffix = []string{"typecode", "value"}[i]
139+
case *types.Slice:
140+
suffix = []string{"data", "len", "cap"}[i]
141+
case *types.Struct:
142+
suffix = goType.Field(i).Name()
143+
case *types.Basic:
144+
switch goType.Kind() {
145+
case types.Complex64, types.Complex128:
146+
suffix = []string{"r", "i"}[i]
147+
case types.String:
148+
suffix = []string{"data", "len"}[i]
149+
}
150+
case *types.Signature:
151+
suffix = []string{"context", "funcptr"}[i]
152+
}
123153
}
124-
fields = append(fields, subfields...)
125-
fieldFlags = append(fieldFlags, subfieldFlags...)
154+
subInfos := flattenAggregateType(subfield, name+"."+suffix, extractSubfield(goType, i))
155+
for i := range subInfos {
156+
subInfos[i].flags |= typeFlags
157+
}
158+
paramInfos = append(paramInfos, subInfos...)
126159
}
127-
return fields, fieldFlags
160+
return paramInfos
128161
default:
129-
return []llvm.Type{t}, []paramFlags{typeFlags}
162+
return []paramInfo{
163+
{
164+
llvmType: t,
165+
name: name,
166+
flags: typeFlags,
167+
},
168+
}
130169
}
131170
}
132171

@@ -226,7 +265,7 @@ func (b *builder) collapseFormalParam(t llvm.Type, fields []llvm.Value) llvm.Val
226265
func (b *builder) collapseFormalParamInternal(t llvm.Type, fields []llvm.Value) (llvm.Value, []llvm.Value) {
227266
switch t.TypeKind() {
228267
case llvm.StructTypeKind:
229-
flattened, _ := flattenAggregateType(t, nil)
268+
flattened := flattenAggregateType(t, "", nil)
230269
if len(flattened) <= maxFieldsPerParam {
231270
value := llvm.ConstNull(t)
232271
for i, subtyp := range t.StructElementTypes() {

compiler/compiler.go

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -738,21 +738,23 @@ func (c *compilerContext) createFunctionDeclaration(f *ir.Function) {
738738
retType = c.ctx.StructType(results, false)
739739
}
740740

741-
var paramTypes []llvm.Type
742-
var paramTypeVariants []paramFlags
741+
var paramInfos []paramInfo
743742
for _, param := range f.Params {
744743
paramType := c.getLLVMType(param.Type())
745-
paramTypeFragments, paramTypeFragmentVariants := expandFormalParamType(paramType, param.Type())
746-
paramTypes = append(paramTypes, paramTypeFragments...)
747-
paramTypeVariants = append(paramTypeVariants, paramTypeFragmentVariants...)
744+
paramFragmentInfos := expandFormalParamType(paramType, param.Name(), param.Type())
745+
paramInfos = append(paramInfos, paramFragmentInfos...)
748746
}
749747

750748
// Add an extra parameter as the function context. This context is used in
751749
// closures and bound methods, but should be optimized away when not used.
752750
if !f.IsExported() {
753-
paramTypes = append(paramTypes, c.i8ptrType) // context
754-
paramTypes = append(paramTypes, c.i8ptrType) // parent coroutine
755-
paramTypeVariants = append(paramTypeVariants, 0, 0)
751+
paramInfos = append(paramInfos, paramInfo{llvmType: c.i8ptrType, name: "context", flags: 0})
752+
paramInfos = append(paramInfos, paramInfo{llvmType: c.i8ptrType, name: "parentHandle", flags: 0})
753+
}
754+
755+
var paramTypes []llvm.Type
756+
for _, info := range paramInfos {
757+
paramTypes = append(paramTypes, info.llvmType)
756758
}
757759

758760
fnType := llvm.FunctionType(retType, paramTypes, false)
@@ -764,12 +766,12 @@ func (c *compilerContext) createFunctionDeclaration(f *ir.Function) {
764766
}
765767

766768
dereferenceableOrNullKind := llvm.AttributeKindID("dereferenceable_or_null")
767-
for i, typ := range paramTypes {
768-
if paramTypeVariants[i]&paramIsDeferenceableOrNull == 0 {
769+
for i, info := range paramInfos {
770+
if info.flags&paramIsDeferenceableOrNull == 0 {
769771
continue
770772
}
771-
if typ.TypeKind() == llvm.PointerTypeKind {
772-
el := typ.ElementType()
773+
if info.llvmType.TypeKind() == llvm.PointerTypeKind {
774+
el := info.llvmType.ElementType()
773775
size := c.targetData.TypeAllocSize(el)
774776
if size == 0 {
775777
// dereferenceable_or_null(0) appears to be illegal in LLVM.
@@ -911,9 +913,10 @@ func (b *builder) createFunctionDefinition() {
911913
for _, param := range b.fn.Params {
912914
llvmType := b.getLLVMType(param.Type())
913915
fields := make([]llvm.Value, 0, 1)
914-
fieldFragments, _ := expandFormalParamType(llvmType, nil)
915-
for range fieldFragments {
916-
fields = append(fields, b.fn.LLVMFn.Param(llvmParamIndex))
916+
for _, info := range expandFormalParamType(llvmType, param.Name(), param.Type()) {
917+
param := b.fn.LLVMFn.Param(llvmParamIndex)
918+
param.SetName(info.name)
919+
fields = append(fields, param)
917920
llvmParamIndex++
918921
}
919922
b.locals[param] = b.collapseFormalParam(llvmType, fields)

compiler/func.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,15 @@ func (c *compilerContext) getRawFuncType(typ *types.Signature) llvm.Type {
125125
// The receiver is not an interface, but a i8* type.
126126
recv = c.i8ptrType
127127
}
128-
recvFragments, _ := expandFormalParamType(recv, nil)
129-
paramTypes = append(paramTypes, recvFragments...)
128+
for _, info := range expandFormalParamType(recv, "", nil) {
129+
paramTypes = append(paramTypes, info.llvmType)
130+
}
130131
}
131132
for i := 0; i < typ.Params().Len(); i++ {
132133
subType := c.getLLVMType(typ.Params().At(i).Type())
133-
paramTypeFragments, _ := expandFormalParamType(subType, nil)
134-
paramTypes = append(paramTypes, paramTypeFragments...)
134+
for _, info := range expandFormalParamType(subType, "", nil) {
135+
paramTypes = append(paramTypes, info.llvmType)
136+
}
135137
}
136138
// All functions take these parameters at the end.
137139
paramTypes = append(paramTypes, c.i8ptrType) // context

compiler/interface.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,10 @@ func (c *compilerContext) getInterfaceInvokeWrapper(f *ir.Function) llvm.Value {
446446

447447
// Get the expanded receiver type.
448448
receiverType := c.getLLVMType(f.Params[0].Type())
449-
expandedReceiverType, _ := expandFormalParamType(receiverType, nil)
449+
var expandedReceiverType []llvm.Type
450+
for _, info := range expandFormalParamType(receiverType, "", nil) {
451+
expandedReceiverType = append(expandedReceiverType, info.llvmType)
452+
}
450453

451454
// Does this method even need any wrapping?
452455
if len(expandedReceiverType) == 1 && receiverType.TypeKind() == llvm.PointerTypeKind {

0 commit comments

Comments
 (0)