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 package main
86
87
88
89
90
91
92
93
94
95
96
97 import (
98 "cmp"
99 "flag"
100 "fmt"
101 "log"
102 "maps"
103 "os"
104 "path/filepath"
105 "runtime/pprof"
106 "slices"
107 "strings"
108
109 "simd/archsimd/_gen/simdgen/arm64"
110 "simd/archsimd/_gen/unify"
111
112 "gopkg.in/yaml.v3"
113 )
114
115 var (
116 xedPath = flag.String("xedPath", "", "load XED datafiles from `path`")
117 arm64Path = flag.String("arm64Path", "", "load ARM64 instruction xml definitions from `path`")
118 flagQ = flag.String("q", "", "query: read `def` as another input (skips final validation)")
119 flagO = flag.String("o", "yaml", "output type: yaml, godefs (generate definitions into a Go source tree")
120 flagGoDefRoot = flag.String("goroot", ".", "the path to the Go dev directory that will receive the generated files")
121 FlagNoDedup = flag.Bool("nodedup", false, "disable deduplicating godefs of 2 qualifying operations from different extensions")
122 FlagNoConstImmPorting = flag.Bool("noconstimmporting", false, "disable const immediate porting from op to imm operand")
123
124
125 FlagArch = flag.String("arch", "must be specified, amd64 or arm64", "the target architecture")
126
127 Verbose = flag.Bool("v", false, "verbose")
128
129 flagDebugXED = flag.Bool("debug-xed", false, "show XED instructions")
130 flagDebugUnify = flag.Bool("debug-unify", false, "print unification trace")
131 flagDebugHTML = flag.String("debug-html", "", "write unification trace to `file.html`")
132 FlagReportDup = flag.Bool("reportdup", false, "report the duplicate godefs")
133
134 flagCPUProfile = flag.String("cpuprofile", "", "write CPU profile to `file`")
135 flagMemProfile = flag.String("memprofile", "", "write memory profile to `file`")
136 )
137
138 const simdPackage = "simd/archsimd"
139
140 func main() {
141 flag.Parse()
142
143 if *flagCPUProfile != "" {
144 f, err := os.Create(*flagCPUProfile)
145 if err != nil {
146 log.Fatalf("-cpuprofile: %s", err)
147 }
148 defer f.Close()
149 pprof.StartCPUProfile(f)
150 defer pprof.StopCPUProfile()
151 }
152 if *flagMemProfile != "" {
153 f, err := os.Create(*flagMemProfile)
154 if err != nil {
155 log.Fatalf("-memprofile: %s", err)
156 }
157 defer func() {
158 pprof.WriteHeapProfile(f)
159 f.Close()
160 }()
161 }
162
163
164 if *arm64Path != "" && *FlagArch != "arm64" {
165 if *xedPath != "" {
166 log.Fatalf("both -xedPath and -arm64Path specified")
167 }
168
169 }
170
171
172 var defs []*unify.Value
173 switch *FlagArch {
174 case "amd64":
175 if *xedPath != "" {
176 defs = loadXED(*xedPath)
177 }
178 case "arm64":
179 if *arm64Path != "" {
180 var err error
181 defs, err = arm64.Load(*arm64Path)
182 if err != nil {
183 log.Fatalf("loading ARM64 instructions: %s", err)
184 }
185 }
186 default:
187 log.Fatalf("simdgen only supports amd64 and arm64")
188 }
189
190 var inputs []unify.Closure
191 inputs = append(inputs, unify.NewSum(defs...))
192
193
194 if *flagQ != "" {
195 r := strings.NewReader(*flagQ)
196 def, err := unify.Read(r, "<query>", unify.ReadOpts{})
197 if err != nil {
198 log.Fatalf("parsing -q: %s", err)
199 }
200 inputs = append(inputs, def)
201 }
202
203
204 must := make(map[*unify.Value]struct{})
205 for _, path := range flag.Args() {
206 defs, err := unify.ReadFile(path, unify.ReadOpts{})
207 if err != nil {
208 log.Fatal(err)
209 }
210 inputs = append(inputs, defs)
211
212 base := filepath.Base(path)
213 if base == "go_amd64.yaml" || base == "go_arm64.yaml" {
214
215 for def := range defs.Summands() {
216 must[def] = struct{}{}
217 }
218 }
219 }
220
221
222 if *flagDebugUnify {
223 unify.Debug.UnifyLog = os.Stderr
224 }
225 if *flagDebugHTML != "" {
226 f, err := os.Create(*flagDebugHTML)
227 if err != nil {
228 log.Fatal(err)
229 }
230 unify.Debug.HTML = f
231 defer f.Close()
232 }
233
234
235 unified, err := unify.Unify(inputs...)
236 if err != nil {
237 log.Fatal(err)
238 }
239
240 ok := true
241
242
243
244
245
246
247 if *flagQ == "" && len(must) > 0 {
248 ok = validate(unified, must)
249 }
250
251
252 switch *flagO {
253 case "yaml":
254
255 fmt.Println("!sum")
256 var val1 [1]*unify.Value
257 for val := range unified.All() {
258 val1[0] = val
259
260
261 enc := yaml.NewEncoder(os.Stdout)
262 if err := enc.Encode(val1); err != nil {
263 log.Fatal(err)
264 }
265 enc.Close()
266 }
267 case "godefs":
268 if err := writeGoDefs(*flagGoDefRoot, unified); err != nil {
269 log.Fatalf("Failed writing godefs: %+v", err)
270 }
271 }
272
273 if !*Verbose && *xedPath != "" {
274 if operandRemarks == 0 {
275 fmt.Fprintf(os.Stderr, "XED decoding generated no errors, which is unusual.\n")
276 } else {
277 fmt.Fprintf(os.Stderr, "XED decoding generated %d \"errors\" which is not cause for alarm, use -v for details.\n", operandRemarks)
278 }
279 }
280 if !ok {
281 os.Exit(1)
282 }
283 }
284
285 func validate(cl unify.Closure, required map[*unify.Value]struct{}) bool {
286 ok := true
287
288
289
290 for def := range cl.All() {
291 if _, ok := def.Domain.(unify.Def); !ok {
292 fmt.Fprintf(os.Stderr, "%s: expected Def, got %T\n", def.PosString(), def.Domain)
293 continue
294 }
295
296 if !def.Exact() {
297 fmt.Fprintf(os.Stderr, "%s: def not reduced to an exact value, why is %s:\n", def.PosString(), def.WhyNotExact())
298 fmt.Fprintf(os.Stderr, "\t%s\n", strings.ReplaceAll(def.String(), "\n", "\n\t"))
299 }
300
301 for root := range def.Provenance() {
302 delete(required, root)
303 }
304 }
305
306 unused := slices.SortedFunc(maps.Keys(required),
307 func(a, b *unify.Value) int {
308 return cmp.Or(
309 cmp.Compare(a.Pos().Path, b.Pos().Path),
310 cmp.Compare(a.Pos().Line, b.Pos().Line),
311 )
312 })
313 for _, def := range unused {
314
315
316
317
318
319
320
321 fmt.Fprintf(os.Stderr, "%s: def required, but did not unify (%v)\n",
322 def.PosString(), def)
323 ok = false
324 }
325 return ok
326 }
327
View as plain text