@@ -2,6 +2,7 @@ package compiler
22
33import (
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.
1415const 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.
1827type 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 {
91104func (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
226265func (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 () {
0 commit comments