blob: 5061de7110c6105db1fce1966e0f3b1ad921aea7 [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.
// Run all SIMD-related code generators.
package main
import (
"flag"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
)
const defaultXedPath = "$XEDPATH" + string(filepath.ListSeparator) + "./simdgen/xeddata" + string(filepath.ListSeparator) + "$HOME/xed/obj/dgen"
var (
flagTmplgen = flag.Bool("tmplgen", true, "run tmplgen generator")
flagSimdgen = flag.Bool("simdgen", true, "run simdgen generator")
flagN = flag.Bool("n", false, "dry run")
flagXedPath = flag.String("xedPath", defaultXedPath, "load XED datafile from `path`, which must be the XED obj/dgen directory")
)
var goRoot string
func main() {
flag.Parse()
if flag.NArg() > 0 {
flag.Usage()
os.Exit(1)
}
if *flagXedPath == defaultXedPath {
// In general we want the shell to do variable expansion, but for the
// default value we don't get that, so do it ourselves.
*flagXedPath = os.ExpandEnv(defaultXedPath)
}
var err error
goRoot, err = resolveGOROOT()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
if *flagTmplgen {
doTmplgen()
}
if *flagSimdgen {
doSimdgen()
}
}
func doTmplgen() {
goRun("-C", "tmplgen", ".")
}
func doSimdgen() {
xedPath, err := resolveXEDPath(*flagXedPath)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
// Regenerate the XED-derived SIMD files
goRun("-C", "simdgen", ".", "-o", "godefs", "-goroot", goRoot, "-xedPath", prettyPath("./simdgen", xedPath), "go.yaml", "types.yaml", "categories.yaml")
// simdgen produces SSA rule files, so update the SSA files
goRun("-C", prettyPath(".", filepath.Join(goRoot, "src", "cmd", "compile", "internal", "ssa", "_gen")), ".")
}
func resolveXEDPath(pathList string) (xedPath string, err error) {
for _, path := range filepath.SplitList(pathList) {
if path == "" {
// Probably an unknown shell variable. Ignore.
continue
}
if _, err := os.Stat(filepath.Join(path, "all-dec-instructions.txt")); err == nil {
return filepath.Abs(path)
}
}
return "", fmt.Errorf("set $XEDPATH or -xedPath to the XED obj/dgen directory")
}
func resolveGOROOT() (goRoot string, err error) {
cmd := exec.Command("go", "env", "GOROOT")
cmd.Stderr = os.Stderr
out, err := cmd.Output()
if err != nil {
return "", fmt.Errorf("%s: %s", cmd, err)
}
goRoot = strings.TrimSuffix(string(out), "\n")
return goRoot, nil
}
func goRun(args ...string) {
exe := filepath.Join(goRoot, "bin", "go")
cmd := exec.Command(exe, append([]string{"run"}, args...)...)
run(cmd)
}
func run(cmd *exec.Cmd) {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
fmt.Fprintf(os.Stderr, "%s\n", cmdString(cmd))
if *flagN {
return
}
if err := cmd.Run(); err != nil {
fmt.Fprintf(os.Stderr, "%s failed: %s\n", cmd, err)
}
}
func prettyPath(base, path string) string {
base, err := filepath.Abs(base)
if err != nil {
return path
}
p, err := filepath.Rel(base, path)
if err != nil {
return path
}
return p
}
func cmdString(cmd *exec.Cmd) string {
// TODO: Shell quoting?
// TODO: Environment.
var buf strings.Builder
cmdPath, err := exec.LookPath(filepath.Base(cmd.Path))
if err == nil && cmdPath == cmd.Path {
cmdPath = filepath.Base(cmdPath)
} else {
cmdPath = prettyPath(".", cmd.Path)
}
buf.WriteString(cmdPath)
for _, arg := range cmd.Args[1:] {
buf.WriteByte(' ')
buf.WriteString(arg)
}
return buf.String()
}