Skip to content

Commit bd330f7

Browse files
committed
internal/simdgen: initial work on Go<->SIMD generator
This can parse XED data into a unifier structure, and unify it with hand-written definitions of SIMD-to-Go mappings. Change-Id: Ie89e328845cde5752ddb3013ebfccc167e85b0bf Reviewed-on: https://go-review.googlesource.com/c/arch/+/667035 Reviewed-by: David Chase <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Junyang Shao <[email protected]>
1 parent ad2912d commit bd330f7

File tree

7 files changed

+695
-0
lines changed

7 files changed

+695
-0
lines changed

internal/simdgen/asm.yaml.toy

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Hand-written toy input like -xedPath would generate.
2+
# This input can be substituted for -xedPath.
3+
!sum
4+
- asm: ADDPS
5+
goarch: amd64
6+
feature: "SSE2"
7+
in:
8+
- asmPos: 0
9+
base: float
10+
bits: 32
11+
w: 128
12+
- asmPos: 1
13+
base: float
14+
bits: 32
15+
w: 128
16+
out:
17+
- asmPos: 0
18+
base: float
19+
bits: 32
20+
w: 128
21+
22+
- asm: ADDPD
23+
goarch: amd64
24+
feature: "SSE2"
25+
in:
26+
- asmPos: 0
27+
base: float
28+
bits: 64
29+
w: 128
30+
- asmPos: 1
31+
base: float
32+
bits: 64
33+
w: 128
34+
out:
35+
- asmPos: 0
36+
base: float
37+
bits: 64
38+
w: 128
39+
40+
- asm: PADDB
41+
goarch: amd64
42+
feature: "SSE2"
43+
in:
44+
- asmPos: 0
45+
base: int|uint
46+
bits: 32
47+
w: 128
48+
- asmPos: 1
49+
base: int|uint
50+
bits: 32
51+
w: 128
52+
out:
53+
- asmPos: 0
54+
base: int|uint
55+
bits: 32
56+
w: 128
57+
58+
- asm: VPADDB
59+
goarch: amd64
60+
feature: "AVX"
61+
in:
62+
- asmPos: 1
63+
base: int|uint
64+
bits: 8
65+
w: 128
66+
- asmPos: 2
67+
base: int|uint
68+
bits: 8
69+
w: 128
70+
out:
71+
- asmPos: 0
72+
base: int|uint
73+
bits: 8
74+
w: 128
75+
76+
- asm: VPADDB
77+
goarch: amd64
78+
feature: "AVX2"
79+
in:
80+
- asmPos: 1
81+
base: int|uint
82+
bits: 8
83+
w: 256
84+
- asmPos: 2
85+
base: int|uint
86+
bits: 8
87+
w: 256
88+
out:
89+
- asmPos: 0
90+
base: int|uint
91+
bits: 8
92+
w: 256

internal/simdgen/categories.yaml

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
!sum
2+
- go: Add
3+
category: binary
4+
- go: AddSaturated
5+
category: binary
6+
- go: Sub
7+
category: binary

internal/simdgen/go.yaml

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
!sum
2+
# For binary operations, we constrain their two inputs and one output to the
3+
# same Go type using a variable.
4+
- go: Add
5+
asm: "V?PADD$xi|V?ADDP$xf"
6+
in:
7+
- go: $t
8+
- go: $t
9+
out:
10+
- go: $t
11+
12+
- go: Sub
13+
goarch: amd64
14+
asm: "V?PSUB$xi|V?SUBP$xf"
15+
in:
16+
- go: $t
17+
- go: $t
18+
out:
19+
- go: $t

internal/simdgen/godefs.go

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Copyright 2025 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import (
8+
"fmt"
9+
"io"
10+
"log"
11+
12+
"golang.org/x/arch/internal/unify"
13+
)
14+
15+
type Operation struct {
16+
Go string // Go method name
17+
Category *string // General operation category (optional)
18+
19+
GoArch string // GOARCH for this definition
20+
Asm string // Assembly mnemonic
21+
22+
In []Operand // Arguments
23+
Out []Operand // Results
24+
}
25+
26+
type Operand struct {
27+
Go string // Go type of this operand
28+
AsmPos int // Position of this operand in the assembly instruction
29+
30+
Base string // Base Go type ("int", "uint", "float")
31+
Bits int // Element bit width
32+
W int // Total vector bit width
33+
}
34+
35+
func writeGoDefs(w io.Writer, cl unify.Closure) {
36+
// TODO: Merge operations with the same signature but multiple
37+
// implementations (e.g., SSE vs AVX)
38+
39+
// TODO: This code is embarrassing, but I'm very tired.
40+
41+
var op Operation
42+
for def := range cl.All() {
43+
if !def.Exact() {
44+
continue
45+
}
46+
if err := def.Decode(&op); err != nil {
47+
log.Println(err.Error())
48+
continue
49+
}
50+
51+
fmt.Fprintf(w, "func (x %s) %s(", op.In[0].Go, op.Go)
52+
for i, arg := range op.In[1:] {
53+
if i > 0 {
54+
fmt.Fprint(w, ", ")
55+
}
56+
fmt.Fprintf(w, "%c %s", 'y'+i, arg.Go)
57+
}
58+
fmt.Fprintf(w, ") (")
59+
for i, res := range op.Out {
60+
if i > 0 {
61+
fmt.Fprint(w, ", ")
62+
}
63+
fmt.Fprintf(w, "%c %s", 'o'+i, res.Go)
64+
}
65+
fmt.Fprintf(w, ") {\n")
66+
67+
asmPosToArg := make(map[int]byte)
68+
asmPosToRes := make(map[int]byte)
69+
for i, arg := range op.In {
70+
asmPosToArg[arg.AsmPos] = 'x' + byte(i)
71+
}
72+
for i, res := range op.Out {
73+
asmPosToRes[res.AsmPos] = 'o' + byte(i)
74+
}
75+
fmt.Fprintf(w, "\t// %s", op.Asm)
76+
for i := 0; ; i++ {
77+
arg, okArg := asmPosToArg[i]
78+
if okArg {
79+
fmt.Fprintf(w, " %c", arg)
80+
}
81+
res, okRes := asmPosToRes[i]
82+
if okRes {
83+
if okArg {
84+
fmt.Fprintf(w, "/")
85+
} else {
86+
fmt.Fprintf(w, " ")
87+
}
88+
fmt.Fprintf(w, "%c", res)
89+
}
90+
if !okArg && !okRes {
91+
break
92+
}
93+
}
94+
fmt.Fprintf(w, "\n")
95+
96+
fmt.Fprintf(w, "}\n")
97+
}
98+
}

0 commit comments

Comments
 (0)