1
2
3
4
5 package ssa
6
7 import (
8 "cmd/compile/internal/types"
9 "cmd/internal/obj"
10 "fmt"
11 "internal/goarch"
12 )
13
14 type localEffect struct {
15 start CPUfeatures
16 internal CPUfeatures
17 end [2]CPUfeatures
18 visited bool
19 }
20
21 func (e localEffect) String() string {
22 return fmt.Sprintf("visited=%v, start=%v, internal=%v, end[0]=%v, end[1]=%v", e.visited, e.start, e.internal, e.end[0], e.end[1])
23 }
24
25
26
27
28 func ifEffect(b *Block) (features CPUfeatures, taken int) {
29
30 if b.Kind != BlockIf {
31 return
32 }
33 c := b.Controls[0]
34
35 if c.Op == OpNot {
36 taken = 1
37 c = c.Args[0]
38 }
39 if c.Op != OpLoad {
40 return
41 }
42 offPtr := c.Args[0]
43 if offPtr.Op != OpOffPtr {
44 return
45 }
46 addr := offPtr.Args[0]
47 if addr.Op != OpAddr || addr.Args[0].Op != OpSB {
48 return
49 }
50 sym := addr.Aux.(*obj.LSym)
51 if sym.Name != "internal/cpu.X86" {
52 return
53 }
54 o := offPtr.AuxInt
55 t := addr.Type
56 if !t.IsPtr() {
57 b.Func.Fatalf("The symbol %s is not a pointer, found %v instead", sym.Name, t)
58 }
59 t = t.Elem()
60 if !t.IsStruct() {
61 b.Func.Fatalf("The referent of symbol %s is not a struct, found %v instead", sym.Name, t)
62 }
63 match := ""
64 for _, f := range t.Fields() {
65 if o == f.Offset && f.Sym != nil {
66 match = f.Sym.Name
67 break
68 }
69 }
70
71 switch match {
72
73 case "HasAVX":
74 features = CPUavx
75 case "HasAVXVNNI":
76 features = CPUavx | CPUavxvnni
77 case "HasAVX2":
78 features = CPUavx2 | CPUavx
79
80
81 case "HasAVX512", "HasAVX512F", "HasAVX512CD", "HasAVX512BW",
82 "HasAVX512DQ", "HasAVX512VL", "HasAVX512VPCLMULQDQ":
83 features = CPUavx512 | CPUavx2 | CPUavx
84
85 case "HasAVX512GFNI":
86 features = CPUavx512 | CPUgfni | CPUavx2 | CPUavx
87 case "HasAVX512VNNI":
88 features = CPUavx512 | CPUavx512vnni | CPUavx2 | CPUavx
89 case "HasAVX512VBMI":
90 features = CPUavx512 | CPUvbmi | CPUavx2 | CPUavx
91 case "HasAVX512VBMI2":
92 features = CPUavx512 | CPUvbmi2 | CPUavx2 | CPUavx
93 case "HasAVX512BITALG":
94 features = CPUavx512 | CPUbitalg | CPUavx2 | CPUavx
95 case "HasAVX512VPOPCNTDQ":
96 features = CPUavx512 | CPUvpopcntdq | CPUavx2 | CPUavx
97
98 case "HasBMI1":
99 features = CPUvbmi
100 case "HasBMI2":
101 features = CPUvbmi2
102
103
104 case "HasAES", "HasADX", "HasERMS", "HasFSRM", "HasFMA", "HasGFNI", "HasOSXSAVE",
105 "HasPCLMULQDQ", "HasPOPCNT", "HasRDTSCP", "HasSHA",
106 "HasSSE3", "HasSSSE3", "HasSSE41", "HasSSE42":
107
108 }
109 if b.Func.pass.debug > 2 {
110 b.Func.Warnl(b.Pos, "%s, block b%v has features offset %d, match is %s, features is %v", b.Func.Name, b.ID, o, match, features)
111 }
112 return
113 }
114
115 func cpufeatures(f *Func) {
116 arch := f.Config.Ctxt().Arch.Family
117
118 if arch != goarch.AMD64 {
119 return
120 }
121
122 po := f.Postorder()
123
124 effects := make([]localEffect, 1+f.NumBlocks(), 1+f.NumBlocks())
125
126 features := func(t *types.Type) CPUfeatures {
127 if t.IsSIMD() {
128 switch t.Size() {
129 case 16, 32:
130 return CPUavx
131 case 64:
132 return CPUavx512 | CPUavx2 | CPUavx
133 }
134 }
135 return CPUNone
136 }
137
138
139
140
141 for i := len(po) - 1; i >= 0; i-- {
142 b := po[i]
143
144 var feat CPUfeatures
145
146 if b == f.Entry {
147
148
149 if f.Type != nil {
150 for _, field := range f.Type.RecvParamsResults() {
151 feat |= features(field.Type)
152 }
153 }
154
155 } else {
156
157 feat = CPUAll
158 for _, p := range b.Preds {
159 pb := p.Block()
160 if !effects[pb.ID].visited {
161
162 continue
163 }
164 pi := p.Index()
165 if pb.Kind != BlockIf {
166 pi = 0
167 }
168
169 feat &= effects[pb.ID].end[pi]
170 }
171 }
172
173 e := localEffect{start: feat, visited: true}
174
175
176 var internal CPUfeatures
177 for _, v := range b.Values {
178
179
180
181
182 t := v.Type
183 if t.IsResults() {
184 for i := 0; i < t.NumFields(); i++ {
185 feat |= features(t.FieldType(i))
186 }
187 } else {
188 internal |= features(v.Type)
189 }
190 }
191 e.internal = internal
192 feat |= internal
193
194 branchEffect, taken := ifEffect(b)
195 e.end = [2]CPUfeatures{feat, feat}
196 e.end[taken] |= branchEffect
197
198 effects[b.ID] = e
199 if f.pass.debug > 1 && feat != CPUNone {
200 f.Warnl(b.Pos, "%s, block b%v has features %v", b.Func.Name, b.ID, feat)
201 }
202
203 b.CPUfeatures = feat
204 f.maxCPUFeatures |= feat
205 }
206
207
208 change := true
209 for change {
210 change = false
211 for i := len(po) - 1; i >= 0; i-- {
212 b := po[i]
213
214 if b == f.Entry {
215 continue
216 }
217 feat := CPUAll
218 for _, p := range b.Preds {
219 pb := p.Block()
220 pi := p.Index()
221 if pb.Kind != BlockIf {
222 pi = 0
223 }
224 feat &= effects[pb.ID].end[pi]
225 }
226 e := effects[b.ID]
227 if feat == e.start {
228 continue
229 }
230 e.start = feat
231 effects[b.ID] = e
232
233 if f.pass.debug > 1 {
234 f.Warnl(b.Pos, "%s, block b%v saw predecessor feature change", b.Func.Name, b.ID)
235 }
236
237 feat |= e.internal
238 if feat == e.end[0]&e.end[1] {
239 continue
240 }
241
242 branchEffect, taken := ifEffect(b)
243 e.end = [2]CPUfeatures{feat, feat}
244 e.end[taken] |= branchEffect
245
246 effects[b.ID] = e
247 b.CPUfeatures = feat
248 if f.pass.debug > 1 {
249 f.Warnl(b.Pos, "%s, block b%v has new features %v", b.Func.Name, b.ID, feat)
250 }
251 change = true
252 }
253 }
254 if f.pass.debug > 0 {
255 for _, b := range f.Blocks {
256 if b.CPUfeatures != CPUNone {
257 f.Warnl(b.Pos, "%s, block b%v has features %v", b.Func.Name, b.ID, b.CPUfeatures)
258 }
259
260 }
261 }
262 }
263
View as plain text