@@ -2,6 +2,7 @@ package compiler
2
2
3
3
import (
4
4
"go/types"
5
+ "strconv"
5
6
6
7
"tinygo.org/x/go-llvm"
7
8
)
@@ -13,6 +14,14 @@ import (
13
14
// a struct contains more fields, it is passed as a struct without expanding.
14
15
const maxFieldsPerParam = 3
15
16
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
+
16
25
// paramFlags identifies parameter attributes for flags. Most importantly, it
17
26
// determines which parameters are dereferenceable_or_null and which aren't.
18
27
type paramFlags uint8
@@ -48,19 +57,23 @@ func (b *builder) createCall(fn llvm.Value, args []llvm.Value, name string) llvm
48
57
49
58
// Expand an argument type to a list that can be used in a function call
50
59
// 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 {
52
61
switch t .TypeKind () {
53
62
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
57
66
} else {
58
67
// failed to lower
59
- return []llvm.Type {t }, []paramFlags {getTypeFlags (goType )}
60
68
}
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
+ },
64
77
}
65
78
}
66
79
@@ -91,10 +104,10 @@ func (b *builder) expandFormalParamOffsets(t llvm.Type) []uint64 {
91
104
func (b * builder ) expandFormalParam (v llvm.Value ) []llvm.Value {
92
105
switch v .Type ().TypeKind () {
93
106
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 {
96
109
fields := b .flattenAggregate (v )
97
- if len (fields ) != len (fieldTypes ) {
110
+ if len (fields ) != len (fieldInfos ) {
98
111
panic ("type and value param lowering don't match" )
99
112
}
100
113
return fields
@@ -110,23 +123,49 @@ func (b *builder) expandFormalParam(v llvm.Value) []llvm.Value {
110
123
111
124
// Try to flatten a struct type to a list of types. Returns a 1-element slice
112
125
// 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 {
114
127
typeFlags := getTypeFlags (goType )
115
128
switch t .TypeKind () {
116
129
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 ())
119
131
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
+ }
123
153
}
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 ... )
126
159
}
127
- return fields , fieldFlags
160
+ return paramInfos
128
161
default :
129
- return []llvm.Type {t }, []paramFlags {typeFlags }
162
+ return []paramInfo {
163
+ {
164
+ llvmType : t ,
165
+ name : name ,
166
+ flags : typeFlags ,
167
+ },
168
+ }
130
169
}
131
170
}
132
171
@@ -226,7 +265,7 @@ func (b *builder) collapseFormalParam(t llvm.Type, fields []llvm.Value) llvm.Val
226
265
func (b * builder ) collapseFormalParamInternal (t llvm.Type , fields []llvm.Value ) (llvm.Value , []llvm.Value ) {
227
266
switch t .TypeKind () {
228
267
case llvm .StructTypeKind :
229
- flattened , _ := flattenAggregateType (t , nil )
268
+ flattened := flattenAggregateType (t , "" , nil )
230
269
if len (flattened ) <= maxFieldsPerParam {
231
270
value := llvm .ConstNull (t )
232
271
for i , subtyp := range t .StructElementTypes () {
0 commit comments