1
2
3
4
5 package sve
6
7 import (
8 "slices"
9 "sort"
10
11 "simd/archsimd/_gen/unify"
12
13 "golang.org/x/arch/arm64/instgen/xmlspec"
14 )
15
16
17
18 func parseInstructions(path string) ([]*Instruction, error) {
19 xmlInsts := xmlspec.ParseXMLFiles(path)
20
21
22
23 var insts []*Instruction
24 for _, xmlInst := range xmlInsts {
25 if xmlInst == nil {
26 continue
27 }
28 for i := range xmlInst.Instruction.Classes.Iclass {
29 inst := &Instruction{
30 Instruction: xmlInst.Instruction,
31 iclass: &xmlInst.Instruction.Classes.Iclass[i],
32 }
33 if inst.mnemonic() == "" || !inst.isSVE() {
34
35 continue
36 }
37 insts = append(insts, inst)
38 }
39 }
40
41 sort.Slice(insts, func(i, j int) bool {
42 return insts[i].mnemonic() < insts[j].mnemonic()
43 })
44 return insts, nil
45 }
46
47
48
49 func Load(path string) ([]*unify.Value, error) {
50 insts, err := parseInstructions(path)
51 if err != nil {
52 return nil, err
53 }
54 covered := groupPredicationForms(insts)
55 var defs []*unify.Value
56 for _, inst := range insts {
57 if covered[inst] {
58
59
60 continue
61 }
62 defs = append(defs, inst.emitAll()...)
63 }
64 return defs, nil
65 }
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 func groupPredicationForms(insts []*Instruction) map[*Instruction]bool {
83 type group struct{ unpred, pred []*Instruction }
84 groups := map[string]*group{}
85 for _, inst := range insts {
86 key := inst.predicationGroupKey()
87 if key == "" {
88 continue
89 }
90 g := groups[key]
91 if g == nil {
92 g = &group{}
93 groups[key] = g
94 }
95 if inst.predicationForm() == "unpredicated" {
96 g.unpred = append(g.unpred, inst)
97 } else {
98 g.pred = append(g.pred, inst)
99 }
100 }
101
102 covered := map[*Instruction]bool{}
103 for _, g := range groups {
104 if len(g.unpred) == 0 && len(g.pred) > 1 {
105 groupPredicatedOnly(g.pred, covered)
106 continue
107 }
108 if len(g.unpred) != 1 || len(g.pred) == 0 {
109
110
111 continue
112 }
113 un := g.unpred[0]
114 unOps := un.operands()
115 var variants []predVariant
116 for _, pr := range g.pred {
117 prOps := pr.operands()
118 if !sameOperandShape(unOps, prOps) {
119 continue
120 }
121 var quals string
122 for _, q := range predicationVariants(prOps) {
123 quals += q
124 }
125 if quals == "" {
126 continue
127 }
128
129
130 outs, ins := splitRegNames(prOps)
131 variants = append(variants, predVariant{quals: quals, outRegNames: outs, inRegNames: ins, predAsmPos: governingAsmPos(prOps)})
132 covered[pr] = true
133 }
134 if len(variants) == 0 {
135 continue
136 }
137 un.predVariants = variants
138 }
139 return covered
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165 func groupPredicatedOnly(pred []*Instruction, covered map[*Instruction]bool) {
166 byQual := map[string]*Instruction{}
167 shape := pred[0].operands()
168 for _, inst := range pred {
169 ops := inst.operands()
170 if !sameOperandShape(shape, ops) {
171 return
172 }
173 quals := predicationVariants(ops)
174 if len(quals) != 1 || quals[0] == "" {
175 return
176 }
177 if _, dup := byQual[quals[0]]; dup {
178 return
179 }
180 byQual[quals[0]] = inst
181 }
182 base, ok := byQual["M"]
183 if !ok {
184 return
185 }
186 baseOps := base.operands()
187 outs, ins := splitRegNames(baseOps)
188 base.predVariants = []predVariant{{quals: "M", outRegNames: outs, inRegNames: ins, predAsmPos: governingAsmPos(baseOps)}}
189 for _, inst := range byQual {
190 if inst != base {
191 covered[inst] = true
192 }
193 }
194 }
195
196
197
198
199 func governingAsmPos(ops []Operand) int {
200 for i := range ops {
201 if ops[i].governing {
202 return ops[i].AsmPos
203 }
204 }
205 panic("sve: predicated encoding has no governing predicate")
206 }
207
208
209
210
211 func splitRegNames(ops []Operand) (outs, ins []string) {
212 for i := range ops {
213 if ops[i].governing {
214 continue
215 }
216 if ops[i].role == "destination" {
217 outs = append(outs, ops[i].regName)
218 } else {
219 ins = append(ins, ops[i].regName)
220 }
221 }
222 return outs, ins
223 }
224
225
226
227
228
229
230 func sameOperandShape(a, b []Operand) bool {
231 split := func(ops []Operand) (outs, ins []string) {
232 for i := range ops {
233 if ops[i].governing {
234 continue
235 }
236 if ops[i].role == "destination" {
237 outs = append(outs, ops[i].Class)
238 } else {
239 ins = append(ins, ops[i].Class)
240 }
241 }
242 return outs, ins
243 }
244 ao, ai := split(a)
245 bo, bi := split(b)
246 return slices.Equal(ao, bo) && slices.Equal(ai, bi)
247 }
248
View as plain text