@@ -58,6 +58,29 @@ func expandCalls(f *Func) {
58
58
return t .IsStruct () || t .IsArray () || regSize == 4 && t .Size () > 4 && t .IsInteger ()
59
59
}
60
60
61
+ // removeTrivialWrapperTypes unwraps layers of
62
+ // struct { singleField SomeType } and [1]SomeType
63
+ // until a non-wrapper type is reached. This is useful
64
+ // for working with assignments to/from interface data
65
+ // fields (either second operand to OpIMake or OpIData)
66
+ // where the wrapping or type conversion can be elided
67
+ // because of type conversions/assertions in source code
68
+ // that do not appear in SSA.
69
+ removeTrivialWrapperTypes := func (t * types.Type ) * types.Type {
70
+ for {
71
+ if t .IsStruct () && t .NumFields () == 1 {
72
+ t = t .Field (0 ).Type
73
+ continue
74
+ }
75
+ if t .IsArray () && t .NumElem () == 1 {
76
+ t = t .Elem ()
77
+ continue
78
+ }
79
+ break
80
+ }
81
+ return t
82
+ }
83
+
61
84
// Calls that need lowering have some number of inputs, including a memory input,
62
85
// and produce a tuple of (value1, value2, ..., mem) where valueK may or may not be SSA-able.
63
86
@@ -84,14 +107,15 @@ func expandCalls(f *Func) {
84
107
// rewrite v as a Copy of call -- the replacement call will produce a mem.
85
108
leaf .copyOf (call )
86
109
} else {
87
- leafType := leaf .Type
110
+ leafType := removeTrivialWrapperTypes ( leaf .Type )
88
111
pt := types .NewPtr (leafType )
89
112
if canSSAType (leafType ) {
90
113
off := f .ConstOffPtrSP (pt , offset + aux .OffsetOfResult (which ), sp )
91
114
// Any selection right out of the arg area/registers has to be same Block as call, use call as mem input.
92
115
if leaf .Block == call .Block {
93
116
leaf .reset (OpLoad )
94
117
leaf .SetArgs2 (off , call )
118
+ leaf .Type = leafType
95
119
} else {
96
120
w := call .Block .NewValue2 (leaf .Pos , OpLoad , leafType , off , call )
97
121
leaf .copyOf (w )
@@ -192,26 +216,31 @@ func expandCalls(f *Func) {
192
216
193
217
case types .TARRAY :
194
218
elt := t .Elem ()
219
+ if src .Op == OpIData && t .NumElem () == 1 && t .Width == regSize && elt .Width == regSize {
220
+ t = removeTrivialWrapperTypes (t )
221
+ if t .Etype == types .TSTRUCT || t .Etype == types .TARRAY {
222
+ f .Fatalf ("Did not expect to find IDATA-immediate with non-trivial struct/array in it" )
223
+ }
224
+ break // handle the leaf type.
225
+ }
195
226
for i := int64 (0 ); i < t .NumElem (); i ++ {
196
227
sel := src .Block .NewValue1I (pos , OpArraySelect , elt , i , src )
197
228
mem = splitStore (dst , sel , mem , v , elt , offset + i * elt .Width , firstStorePos )
198
229
firstStorePos = firstStorePos .WithNotStmt ()
199
230
}
200
231
return mem
201
232
case types .TSTRUCT :
202
- if src .Op == OpIData && t .NumFields () == 1 && t .Field (0 ).Type .Width == t .Width && t .Width == regSize {
233
+ if src .Op == OpIData && t .NumFields () == 1 && t .Field (0 ).Type .Width == t .Width && t .Width == regSize {
203
234
// This peculiar test deals with accesses to immediate interface data.
204
235
// It works okay because everything is the same size.
205
236
// Example code that triggers this can be found in go/constant/value.go, function ToComplex
206
237
// v119 (+881) = IData <intVal> v6
207
238
// v121 (+882) = StaticLECall <floatVal,mem> {AuxCall{"".itof([intVal,0])[floatVal,8]}} [16] v119 v1
208
239
// This corresponds to the generic rewrite rule "(StructSelect [0] (IData x)) => (IData x)"
209
240
// Guard against "struct{struct{*foo}}"
210
- for t .Etype == types .TSTRUCT && t .NumFields () == 1 {
211
- t = t .Field (0 ).Type
212
- }
241
+ t = removeTrivialWrapperTypes (t )
213
242
if t .Etype == types .TSTRUCT || t .Etype == types .TARRAY {
214
- f .Fatalf ("Did not expect to find IDATA-immediate with non-trivial struct in it" )
243
+ f .Fatalf ("Did not expect to find IDATA-immediate with non-trivial struct/array in it" )
215
244
}
216
245
break // handle the leaf type.
217
246
}
0 commit comments