1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package compare
import (
"cmd/compile/internal/base"
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/src"
"cmd/internal/sys"
"testing"
)
type typefn func() *types.Type
func init() {
// These are the few constants that need to be initialized in order to use
// the types package without using the typecheck package by calling
// typecheck.InitUniverse() (the normal way to initialize the types package).
types.PtrSize = 8
types.RegSize = 8
types.MaxWidth = 1 << 50
typecheck.InitUniverse()
base.Ctxt = &obj.Link{Arch: &obj.LinkArch{Arch: &sys.Arch{Alignment: 1, CanMergeLoads: true}}}
}
func TestEqStructCost(t *testing.T) {
repeat := func(n int, typ *types.Type) []*types.Type {
typs := make([]*types.Type, n)
for i := range typs {
typs[i] = typ
}
return typs
}
tt := []struct {
name string
cost int64
nonMergeLoadCost int64
fieldTypes []*types.Type
}{
{"struct without fields", 0, 0, nil},
{"struct with 1 byte field", 1, 1, repeat(1, types.ByteType)},
{"struct with 8 byte fields", 1, 8, repeat(8, types.ByteType)},
{"struct with 16 byte fields", 2, 16, repeat(16, types.ByteType)},
{"struct with 32 byte fields", 4, 32, repeat(32, types.ByteType)},
{"struct with 2 int32 fields", 1, 2, repeat(2, types.Types[types.TINT32])},
{"struct with 2 int32 fields and 1 int64", 2, 3,
[]*types.Type{
types.Types[types.TINT32],
types.Types[types.TINT32],
types.Types[types.TINT64],
},
},
{"struct with 1 int field and 1 string", 3, 3,
[]*types.Type{
types.Types[types.TINT64],
types.Types[types.TSTRING],
},
},
{"struct with 2 strings", 4, 4, repeat(2, types.Types[types.TSTRING])},
{"struct with 1 large byte array field", 26, 101,
[]*types.Type{
types.NewArray(types.Types[types.TUINT16], 101),
},
},
{"struct with string array field", 4, 4,
[]*types.Type{
types.NewArray(types.Types[types.TSTRING], 2),
},
},
}
for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
fields := make([]*types.Field, len(tc.fieldTypes))
for i, ftyp := range tc.fieldTypes {
fields[i] = types.NewField(src.NoXPos, typecheck.LookupNum("f", i), ftyp)
}
typ := types.NewStruct(fields)
types.CalcSize(typ)
want := tc.cost
base.Ctxt.Arch.CanMergeLoads = true
actual := EqStructCost(typ)
if actual != want {
t.Errorf("CanMergeLoads=true EqStructCost(%v) = %d, want %d", typ, actual, want)
}
base.Ctxt.Arch.CanMergeLoads = false
want = tc.nonMergeLoadCost
actual = EqStructCost(typ)
if actual != want {
t.Errorf("CanMergeLoads=false EqStructCost(%v) = %d, want %d", typ, actual, want)
}
})
}
}
|