blob: 10222bc71aec26137cab0bcc6700889ced90f880 [file] [log] [blame]
// 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 .ImmFirst) 0}}
// Imm
case {{.ImmFirst}}:
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 .VregFirst) 0}}
// vreg
case {{.VregFirst}}:
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 .VregSecond) 0}}
// vreg
case {{.VregSecond}}:
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 .VregThird) 0}}
// vreg
case {{.VregThird}}:
if p.From.Type == obj.TYPE_CONST {
p.AddRestSourceReg(simdReg(v.Args[1]))
} else {
p.AddRestSourceReg(simdReg(v.Args[2]))
}
{{end}}{{if gt (len .MaskThird) 0}}
// k mask
case {{.MaskThird}}:
if p.From.Type == obj.TYPE_CONST {
p.AddRestSourceReg(v.Args[1].Reg())
} else {
p.AddRestSourceReg(v.Args[2].Reg())
}{{end}}
}
// Fourth arg
switch v.Op {{"{"}}{{if gt (len .MaskFourth) 0}}
case {{.MaskFourth}}:
if p.From.Type == obj.TYPE_CONST {
p.AddRestSourceReg(v.Args[2].Reg())
} else {
p.AddRestSourceReg(v.Args[3].Reg())
}{{end}}
}
// Output
switch v.Op {{"{"}}{{if gt (len .VregOut) 0}}
case {{.VregOut}}:
p.To.Type = obj.TYPE_REG
p.To.Reg = simdReg(v)
{{end}}{{if gt (len .MaskOut) 0}}
case {{.MaskOut}}:
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
{{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 ImmFirst []string
var VregFirst []string
var VregSecond []string
var MaskThird []string
var VregThird []string
var MaskFourth []string
var VregOut []string
var MaskOut []string
var ZeroingMask []string
seen := map[string]struct{}{}
for _, op := range ops {
asm := op.Asm
shapeIn, shapeOut, 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 == PureVregIn || shapeIn == PureKmaskIn {
// Masks and vreg are handled together by simdReg()
VregFirst = append(VregFirst, caseStr)
if len(gOp.In) > 1 {
VregSecond = append(VregSecond, caseStr)
}
} else if shapeIn == OneKmaskIn {
VregFirst = append(VregFirst, caseStr)
VregSecond = append(VregSecond, caseStr)
MaskThird = append(MaskThird, caseStr)
if gOp.Zeroing == nil {
ZeroingMask = append(ZeroingMask, caseStr)
}
} else if shapeIn == OneConstImmIn {
ImmFirst = append(ImmFirst, caseStr)
VregSecond = append(VregSecond, caseStr)
VregThird = append(VregThird, caseStr)
} else {
// OneKmaskConstImmIn case
ImmFirst = append(ImmFirst, caseStr)
VregSecond = append(VregSecond, caseStr)
VregThird = append(VregThird, caseStr)
MaskFourth = append(MaskFourth, caseStr)
if gOp.Zeroing == nil {
ZeroingMask = append(ZeroingMask, caseStr)
}
}
if shapeOut == OneVregOut || gOp.Out[0].OverwriteClass != nil {
// If class overwrite is happening, that's not really a mask but a vreg.
VregOut = append(VregOut, caseStr)
} else {
// OneKmaskOut case
MaskOut = append(MaskOut, caseStr)
}
}
data := struct {
ImmFirst string
VregFirst string
VregSecond string
MaskThird string
VregThird string
MaskFourth string
VregOut string
MaskOut string
ZeroingMask string
}{
strings.Join(ImmFirst, ", "),
strings.Join(VregFirst, ", "),
strings.Join(VregSecond, ", "),
strings.Join(MaskThird, ", "),
strings.Join(VregThird, ", "),
strings.Join(MaskFourth, ", "),
strings.Join(VregOut, ", "),
strings.Join(MaskOut, ", "),
strings.Join(ZeroingMask, ", "),
}
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
}