blob: 1f61d071cff91bbdab496b0a0d1dd375692fc7cb [file]
// Copyright 2025 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 main
import (
"fmt"
"strings"
)
const simdssaTmpl = `// Code generated by x/arch/internal/simdgen using 'go run . -xedPath $XED_PATH -o godefs -goroot $GOROOT go.yaml types.yaml categories.yaml'; DO NOT EDIT.
package amd64
import (
"cmd/compile/internal/ssa"
"cmd/compile/internal/ssagen"
"cmd/internal/obj"
"cmd/internal/obj/x86"
)
func ssaGenSIMDValue(s *ssagen.State, v *ssa.Value) bool {
p := s.Prog(v.Op.Asm())
// First arg
switch v.Op {{"{"}}{{if gt (len .Imms) 0}}
// Immediates
case {{.Imms}}:
imm := v.AuxInt
if imm < 0 || imm > 255 {
v.Fatalf("Invalid source selection immediate")
}
p.From.Offset = imm
p.From.Type = obj.TYPE_CONST
{{end}}{{if gt (len .Reg0) 0}}
// Registers
case {{.Reg0}}:
p.From.Type = obj.TYPE_REG
p.From.Reg = simdReg(v.Args[0])
{{end}}
default:
// At least one arg is required.
return false
}
// Second arg
switch v.Op {{"{"}}{{if gt (len .Reg1) 0}}
// Registers
case {{.Reg1}}:
if p.From.Type == obj.TYPE_CONST {
p.AddRestSourceReg(simdReg(v.Args[0]))
} else {
p.AddRestSourceReg(simdReg(v.Args[1]))
}{{end}}
}
// Third arg
switch v.Op {{"{"}}{{if gt (len .Reg2) 0}}
// Registers
case {{.Reg2}}:
if p.From.Type == obj.TYPE_CONST {
p.AddRestSourceReg(simdReg(v.Args[1]))
} else {
p.AddRestSourceReg(simdReg(v.Args[2]))
}{{end}}
}
// Fourth arg
switch v.Op {{"{"}}{{if gt (len .Reg3) 0}}
case {{.Reg3}}:
if p.From.Type == obj.TYPE_CONST {
p.AddRestSourceReg(simdReg(v.Args[2]))
} else {
p.AddRestSourceReg(simdReg(v.Args[3]))
}{{end}}
}
// Output
switch v.Op {{"{"}}{{if gt (len .All) 0}}
case {{.All}}:
p.To.Type = obj.TYPE_REG
p.To.Reg = simdReg(v)
{{end}}
default:
// One result is required.
return false
}
{{if gt (len .ZeroingMask) 0}}
// Masked operation are always compiled with zeroing.
switch v.Op {
case {{.ZeroingMask}}:
x86.ParseSuffix(p, "Z")
}
{{end}}
return true
}
`
// writeSIMDSSA generates the ssa to prog lowering codes and writes it to simdssa.go
// within the specified directory.
func writeSIMDSSA(directory string, ops []Operation) error {
var Imms []string
var All []string
var ZeroingMask []string
Regs := map[int][]string{}
seen := map[string]struct{}{}
for _, op := range ops {
asm := op.Asm
shapeIn, _, maskType, _, _, gOp, err := op.shape()
if err != nil {
return err
}
if maskType == 2 {
asm += "Masked"
}
asm = fmt.Sprintf("%s%d", asm, *gOp.Out[0].Bits)
if _, ok := seen[asm]; ok {
continue
}
seen[asm] = struct{}{}
caseStr := fmt.Sprintf("ssa.OpAMD64%s", asm)
if shapeIn == OneKmaskIn || shapeIn == OneKmaskConstImmIn {
if gOp.Zeroing == nil {
ZeroingMask = append(ZeroingMask, caseStr)
}
}
immCount := 0
if shapeIn == OneConstImmIn || shapeIn == OneKmaskConstImmIn {
immCount++
Imms = append(Imms, caseStr)
}
for i := range len(gOp.In) {
if i > 2 {
return fmt.Errorf("simdgen does not recognize more than 3 registers: %s", gOp)
}
Regs[i+immCount] = append(Regs[i+immCount], caseStr)
}
All = append(All, caseStr)
}
data := struct {
Imms string
Reg0 string
Reg1 string
Reg2 string
Reg3 string
All string
ZeroingMask string
}{
strings.Join(Imms, ",\n\t\t"),
strings.Join(Regs[0], ",\n\t\t"),
strings.Join(Regs[1], ",\n\t\t"),
strings.Join(Regs[2], ",\n\t\t"),
strings.Join(Regs[3], ",\n\t\t"),
strings.Join(All, ",\n\t\t"),
strings.Join(ZeroingMask, ",\n\t\t"),
}
file, t, err := openFileAndPrepareTemplate(directory, "src/cmd/compile/internal/amd64/simdssa.go", simdssaTmpl)
if err != nil {
return err
}
defer file.Close()
err = t.Execute(file, data)
if err != nil {
return fmt.Errorf("failed to execute template: %w", err)
}
return nil
}