--- /dev/null
+// 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()
+}