1
2
3
4
5 package test
6
7 import (
8 "bufio"
9 "cmd/compile/internal/abi"
10 "cmd/compile/internal/base"
11 "cmd/compile/internal/ssagen"
12 "cmd/compile/internal/typecheck"
13 "cmd/compile/internal/types"
14 "cmd/internal/obj"
15 "cmd/internal/obj/x86"
16 "cmd/internal/src"
17 "fmt"
18 "os"
19 "testing"
20 )
21
22
23
24
25 var configAMD64 = abi.NewABIConfig(9, 15, 0, 1)
26
27 func TestMain(m *testing.M) {
28 ssagen.Arch.LinkArch = &x86.Linkamd64
29 ssagen.Arch.REGSP = x86.REGSP
30 ssagen.Arch.MAXWIDTH = 1 << 50
31 types.MaxWidth = ssagen.Arch.MAXWIDTH
32 base.Ctxt = obj.Linknew(ssagen.Arch.LinkArch)
33 base.Ctxt.DiagFunc = base.Errorf
34 base.Ctxt.DiagFlush = base.FlushErrors
35 base.Ctxt.Bso = bufio.NewWriter(os.Stdout)
36 types.LocalPkg = types.NewPkg("p", "local")
37 types.LocalPkg.Prefix = "p"
38 types.PtrSize = ssagen.Arch.LinkArch.PtrSize
39 types.RegSize = ssagen.Arch.LinkArch.RegSize
40 typecheck.InitUniverse()
41 os.Exit(m.Run())
42 }
43
44 func TestABIUtilsBasic1(t *testing.T) {
45
46
47 i32 := types.Types[types.TINT32]
48 ft := mkFuncType(nil, []*types.Type{i32}, []*types.Type{i32})
49
50
51 exp := makeExpectedDump(`
52 IN 0: R{ I0 } spilloffset: 0 typ: int32
53 OUT 0: R{ I0 } spilloffset: -1 typ: int32
54 offsetToSpillArea: 0 spillAreaSize: 8
55 `)
56
57 abitest(t, ft, exp)
58 }
59
60 func TestABIUtilsBasic2(t *testing.T) {
61
62
63
64
65
66
67
68
69 i8 := types.Types[types.TINT8]
70 i16 := types.Types[types.TINT16]
71 i32 := types.Types[types.TINT32]
72 i64 := types.Types[types.TINT64]
73 f32 := types.Types[types.TFLOAT32]
74 f64 := types.Types[types.TFLOAT64]
75 c64 := types.Types[types.TCOMPLEX64]
76 c128 := types.Types[types.TCOMPLEX128]
77 ft := mkFuncType(nil,
78 []*types.Type{
79 i8, i16, i32, i64,
80 f32, f32, f64, f64,
81 i8, i16, i32, i64,
82 f32, f32, f64, f64,
83 c128, c128, c128, c128, c64,
84 i8, i16, i32, i64,
85 i8, i16, i32, i64},
86 []*types.Type{i32, f64, f64})
87 exp := makeExpectedDump(`
88 IN 0: R{ I0 } spilloffset: 0 typ: int8
89 IN 1: R{ I1 } spilloffset: 2 typ: int16
90 IN 2: R{ I2 } spilloffset: 4 typ: int32
91 IN 3: R{ I3 } spilloffset: 8 typ: int64
92 IN 4: R{ F0 } spilloffset: 16 typ: float32
93 IN 5: R{ F1 } spilloffset: 20 typ: float32
94 IN 6: R{ F2 } spilloffset: 24 typ: float64
95 IN 7: R{ F3 } spilloffset: 32 typ: float64
96 IN 8: R{ I4 } spilloffset: 40 typ: int8
97 IN 9: R{ I5 } spilloffset: 42 typ: int16
98 IN 10: R{ I6 } spilloffset: 44 typ: int32
99 IN 11: R{ I7 } spilloffset: 48 typ: int64
100 IN 12: R{ F4 } spilloffset: 56 typ: float32
101 IN 13: R{ F5 } spilloffset: 60 typ: float32
102 IN 14: R{ F6 } spilloffset: 64 typ: float64
103 IN 15: R{ F7 } spilloffset: 72 typ: float64
104 IN 16: R{ F8 F9 } spilloffset: 80 typ: complex128
105 IN 17: R{ F10 F11 } spilloffset: 96 typ: complex128
106 IN 18: R{ F12 F13 } spilloffset: 112 typ: complex128
107 IN 19: R{ } offset: 0 typ: complex128
108 IN 20: R{ } offset: 16 typ: complex64
109 IN 21: R{ I8 } spilloffset: 128 typ: int8
110 IN 22: R{ } offset: 24 typ: int16
111 IN 23: R{ } offset: 28 typ: int32
112 IN 24: R{ } offset: 32 typ: int64
113 IN 25: R{ } offset: 40 typ: int8
114 IN 26: R{ } offset: 42 typ: int16
115 IN 27: R{ } offset: 44 typ: int32
116 IN 28: R{ } offset: 48 typ: int64
117 OUT 0: R{ I0 } spilloffset: -1 typ: int32
118 OUT 1: R{ F0 } spilloffset: -1 typ: float64
119 OUT 2: R{ F1 } spilloffset: -1 typ: float64
120 offsetToSpillArea: 56 spillAreaSize: 136
121 `)
122
123 abitest(t, ft, exp)
124 }
125
126 func TestABIUtilsArrays(t *testing.T) {
127
128
129 i32 := types.Types[types.TINT32]
130 ae := types.NewArray(i32, 0)
131 a1 := types.NewArray(i32, 1)
132 a2 := types.NewArray(i32, 2)
133 aa1 := types.NewArray(a1, 1)
134 ft := mkFuncType(nil, []*types.Type{a1, ae, aa1, a2},
135 []*types.Type{a2, a1, ae, aa1})
136
137 exp := makeExpectedDump(`
138 IN 0: R{ I0 } spilloffset: 0 typ: [1]int32
139 IN 1: R{ } offset: 0 typ: [0]int32
140 IN 2: R{ I1 } spilloffset: 4 typ: [1][1]int32
141 IN 3: R{ } offset: 0 typ: [2]int32
142 OUT 0: R{ } offset: 8 typ: [2]int32
143 OUT 1: R{ I0 } spilloffset: -1 typ: [1]int32
144 OUT 2: R{ } offset: 16 typ: [0]int32
145 OUT 3: R{ I1 } spilloffset: -1 typ: [1][1]int32
146 offsetToSpillArea: 16 spillAreaSize: 8
147 `)
148
149 abitest(t, ft, exp)
150 }
151
152 func TestABIUtilsStruct1(t *testing.T) {
153
154
155
156 i8 := types.Types[types.TINT8]
157 i16 := types.Types[types.TINT16]
158 i32 := types.Types[types.TINT32]
159 i64 := types.Types[types.TINT64]
160 s := mkstruct(i8, i8, mkstruct(), i8, i16)
161 ft := mkFuncType(nil, []*types.Type{i8, s, i64},
162 []*types.Type{s, i8, i32})
163
164 exp := makeExpectedDump(`
165 IN 0: R{ I0 } spilloffset: 0 typ: int8
166 IN 1: R{ I1 I2 I3 I4 } spilloffset: 2 typ: struct { int8; int8; struct {}; int8; int16 }
167 IN 2: R{ I5 } spilloffset: 8 typ: int64
168 OUT 0: R{ I0 I1 I2 I3 } spilloffset: -1 typ: struct { int8; int8; struct {}; int8; int16 }
169 OUT 1: R{ I4 } spilloffset: -1 typ: int8
170 OUT 2: R{ I5 } spilloffset: -1 typ: int32
171 offsetToSpillArea: 0 spillAreaSize: 16
172 `)
173
174 abitest(t, ft, exp)
175 }
176
177 func TestABIUtilsStruct2(t *testing.T) {
178
179
180
181
182 f64 := types.Types[types.TFLOAT64]
183 i64 := types.Types[types.TINT64]
184 s := mkstruct(i64, mkstruct())
185 fs := mkstruct(f64, s, mkstruct())
186 ft := mkFuncType(nil, []*types.Type{s, s, fs},
187 []*types.Type{fs, fs})
188
189 exp := makeExpectedDump(`
190 IN 0: R{ I0 } spilloffset: 0 typ: struct { int64; struct {} }
191 IN 1: R{ I1 } spilloffset: 16 typ: struct { int64; struct {} }
192 IN 2: R{ F0 I2 } spilloffset: 32 typ: struct { float64; struct { int64; struct {} }; struct {} }
193 OUT 0: R{ F0 I0 } spilloffset: -1 typ: struct { float64; struct { int64; struct {} }; struct {} }
194 OUT 1: R{ F1 I1 } spilloffset: -1 typ: struct { float64; struct { int64; struct {} }; struct {} }
195 offsetToSpillArea: 0 spillAreaSize: 64
196 `)
197
198 abitest(t, ft, exp)
199 }
200
201
202
203
204 func TestABIUtilsEmptyFieldAtEndOfStruct(t *testing.T) {
205
206
207
208
209 f64 := types.Types[types.TFLOAT64]
210 i64 := types.Types[types.TINT64]
211 i16 := types.Types[types.TINT16]
212 tb := types.Types[types.TBOOL]
213 ab2 := types.NewArray(tb, 2)
214 a2 := types.NewArray(i64, 2)
215 a3 := types.NewArray(i16, 3)
216 empty := mkstruct()
217 s := mkstruct(a2, empty)
218 s2 := mkstruct(a3, empty)
219 fs := mkstruct(f64, s, empty)
220 ft := mkFuncType(nil, []*types.Type{s, ab2, s2, fs, fs},
221 []*types.Type{fs, ab2, fs})
222
223 exp := makeExpectedDump(`
224 IN 0: R{ } offset: 0 typ: struct { [2]int64; struct {} }
225 IN 1: R{ } offset: 24 typ: [2]bool
226 IN 2: R{ } offset: 26 typ: struct { [3]int16; struct {} }
227 IN 3: R{ } offset: 40 typ: struct { float64; struct { [2]int64; struct {} }; struct {} }
228 IN 4: R{ } offset: 80 typ: struct { float64; struct { [2]int64; struct {} }; struct {} }
229 OUT 0: R{ } offset: 120 typ: struct { float64; struct { [2]int64; struct {} }; struct {} }
230 OUT 1: R{ } offset: 160 typ: [2]bool
231 OUT 2: R{ } offset: 168 typ: struct { float64; struct { [2]int64; struct {} }; struct {} }
232 offsetToSpillArea: 208 spillAreaSize: 0
233 `)
234
235 abitest(t, ft, exp)
236
237
238 typ := mkstruct(i64, i64, mkstruct())
239 have := configAMD64.NumParamRegs(typ)
240 if have != 2 {
241 t.Errorf("NumParams(%v): have %v, want %v", typ, have, 2)
242 }
243 }
244
245 func TestABIUtilsSliceString(t *testing.T) {
246
247
248 i32 := types.Types[types.TINT32]
249 sli32 := types.NewSlice(i32)
250 str := types.Types[types.TSTRING]
251 i8 := types.Types[types.TINT8]
252 i64 := types.Types[types.TINT64]
253 ft := mkFuncType(nil, []*types.Type{sli32, i8, sli32, i8, str, i8, i64, sli32},
254 []*types.Type{str, i64, str, sli32})
255
256 exp := makeExpectedDump(`
257 IN 0: R{ I0 I1 I2 } spilloffset: 0 typ: []int32
258 IN 1: R{ I3 } spilloffset: 24 typ: int8
259 IN 2: R{ I4 I5 I6 } spilloffset: 32 typ: []int32
260 IN 3: R{ I7 } spilloffset: 56 typ: int8
261 IN 4: R{ } offset: 0 typ: string
262 IN 5: R{ I8 } spilloffset: 57 typ: int8
263 IN 6: R{ } offset: 16 typ: int64
264 IN 7: R{ } offset: 24 typ: []int32
265 OUT 0: R{ I0 I1 } spilloffset: -1 typ: string
266 OUT 1: R{ I2 } spilloffset: -1 typ: int64
267 OUT 2: R{ I3 I4 } spilloffset: -1 typ: string
268 OUT 3: R{ I5 I6 I7 } spilloffset: -1 typ: []int32
269 offsetToSpillArea: 48 spillAreaSize: 64
270 `)
271
272 abitest(t, ft, exp)
273 }
274
275 func TestABIUtilsMethod(t *testing.T) {
276
277
278
279 i16 := types.Types[types.TINT16]
280 i64 := types.Types[types.TINT64]
281 f64 := types.Types[types.TFLOAT64]
282 s1 := mkstruct(i16, i16, i16)
283 ps1 := types.NewPtr(s1)
284 a7 := types.NewArray(ps1, 7)
285 ft := mkFuncType(s1, []*types.Type{ps1, a7, f64, i16, i16, i16},
286 []*types.Type{a7, f64, i64})
287
288 exp := makeExpectedDump(`
289 IN 0: R{ I0 I1 I2 } spilloffset: 0 typ: struct { int16; int16; int16 }
290 IN 1: R{ I3 } spilloffset: 8 typ: *struct { int16; int16; int16 }
291 IN 2: R{ } offset: 0 typ: [7]*struct { int16; int16; int16 }
292 IN 3: R{ F0 } spilloffset: 16 typ: float64
293 IN 4: R{ I4 } spilloffset: 24 typ: int16
294 IN 5: R{ I5 } spilloffset: 26 typ: int16
295 IN 6: R{ I6 } spilloffset: 28 typ: int16
296 OUT 0: R{ } offset: 56 typ: [7]*struct { int16; int16; int16 }
297 OUT 1: R{ F0 } spilloffset: -1 typ: float64
298 OUT 2: R{ I0 } spilloffset: -1 typ: int64
299 offsetToSpillArea: 112 spillAreaSize: 32
300 `)
301
302 abitest(t, ft, exp)
303 }
304
305 func TestABIUtilsInterfaces(t *testing.T) {
306
307
308
309
310
311 ei := types.Types[types.TINTER]
312 pei := types.NewPtr(ei)
313 fldt := mkFuncType(types.FakeRecvType(), []*types.Type{},
314 []*types.Type{types.Types[types.TSTRING]})
315 field := types.NewField(src.NoXPos, typecheck.Lookup("F"), fldt)
316 nei := types.NewInterface([]*types.Field{field})
317 i16 := types.Types[types.TINT16]
318 tb := types.Types[types.TBOOL]
319 s1 := mkstruct(i16, i16, tb)
320 ft := mkFuncType(nil, []*types.Type{s1, ei, ei, nei, pei, nei, i16},
321 []*types.Type{ei, nei, pei})
322
323 exp := makeExpectedDump(`
324 IN 0: R{ I0 I1 I2 } spilloffset: 0 typ: struct { int16; int16; bool }
325 IN 1: R{ I3 I4 } spilloffset: 8 typ: interface {}
326 IN 2: R{ I5 I6 } spilloffset: 24 typ: interface {}
327 IN 3: R{ I7 I8 } spilloffset: 40 typ: interface { F() string }
328 IN 4: R{ } offset: 0 typ: *interface {}
329 IN 5: R{ } offset: 8 typ: interface { F() string }
330 IN 6: R{ } offset: 24 typ: int16
331 OUT 0: R{ I0 I1 } spilloffset: -1 typ: interface {}
332 OUT 1: R{ I2 I3 } spilloffset: -1 typ: interface { F() string }
333 OUT 2: R{ I4 } spilloffset: -1 typ: *interface {}
334 offsetToSpillArea: 32 spillAreaSize: 56
335 `)
336
337 abitest(t, ft, exp)
338 }
339
340 func TestABINumParamRegs(t *testing.T) {
341 i8 := types.Types[types.TINT8]
342 i16 := types.Types[types.TINT16]
343 i32 := types.Types[types.TINT32]
344 i64 := types.Types[types.TINT64]
345 f32 := types.Types[types.TFLOAT32]
346 f64 := types.Types[types.TFLOAT64]
347 c64 := types.Types[types.TCOMPLEX64]
348 c128 := types.Types[types.TCOMPLEX128]
349
350 s := mkstruct(i8, i8, mkstruct(), i8, i16)
351 a := mkstruct(s, s, s)
352
353 nrtest(t, i8, 1)
354 nrtest(t, i16, 1)
355 nrtest(t, i32, 1)
356 nrtest(t, i64, 1)
357 nrtest(t, f32, 1)
358 nrtest(t, f64, 1)
359 nrtest(t, c64, 2)
360 nrtest(t, c128, 2)
361 nrtest(t, s, 4)
362 nrtest(t, a, 12)
363 }
364
365 func TestABIUtilsComputePadding(t *testing.T) {
366
367 i8 := types.Types[types.TINT8]
368 i16 := types.Types[types.TINT16]
369 i32 := types.Types[types.TINT32]
370 i64 := types.Types[types.TINT64]
371 emptys := mkstruct()
372 s1 := mkstruct(i8, i16, emptys, i32, i64)
373
374 a1 := types.NewArray(i32, 1)
375 ft := mkFuncType(nil, []*types.Type{i32, s1, emptys, a1}, nil)
376
377
378 exp := makeExpectedDump(`
379 IN 0: R{ I0 } spilloffset: 0 typ: int32
380 IN 1: R{ I1 I2 I3 I4 } spilloffset: 8 typ: struct { int8; int16; struct {}; int32; int64 }
381 IN 2: R{ } offset: 0 typ: struct {}
382 IN 3: R{ I5 } spilloffset: 24 typ: [1]int32
383 offsetToSpillArea: 0 spillAreaSize: 32
384 `)
385 abitest(t, ft, exp)
386
387
388
389 regRes := configAMD64.ABIAnalyze(ft, false)
390 padding := make([]uint64, 32)
391 parm := regRes.InParams()[1]
392 padding = parm.ComputePadding(padding)
393 want := "[1 1 1 0]"
394 got := fmt.Sprintf("%+v", padding)
395 if got != want {
396 t.Errorf("padding mismatch: wanted %q got %q\n", got, want)
397 }
398 }
399
View as plain text