cmd/compilebench: use -p, handle packages with asm files

Update compiler invocations to pass "-p <importpath>", since that
is the normal way to invoke the compiler these days.  In addition,
add some logic to generate a 'symabis' file for packages that
include assembly source files.

Change-Id: I64c490c55603609cf2cdbfae20ed787a581be4d3
Reviewed-on: https://go-review.googlesource.com/c/tools/+/405734
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Than McIntosh <thanm@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
diff --git a/cmd/compilebench/main.go b/cmd/compilebench/main.go
index 53d97b7..28dc450 100644
--- a/cmd/compilebench/main.go
+++ b/cmd/compilebench/main.go
@@ -81,23 +81,26 @@
 	"encoding/json"
 	"flag"
 	"fmt"
-	exec "golang.org/x/sys/execabs"
 	"io/ioutil"
 	"log"
 	"os"
 	"path/filepath"
 	"regexp"
+	"runtime"
 	"strconv"
 	"strings"
 	"time"
+
+	exec "golang.org/x/sys/execabs"
 )
 
 var (
-	goroot   string
-	compiler string
-	linker   string
-	runRE    *regexp.Regexp
-	is6g     bool
+	goroot    string
+	compiler  string
+	assembler string
+	linker    string
+	runRE     *regexp.Regexp
+	is6g      bool
 )
 
 var (
@@ -105,6 +108,7 @@
 	flagAlloc          = flag.Bool("alloc", false, "report allocations")
 	flagObj            = flag.Bool("obj", false, "report object file stats")
 	flagCompiler       = flag.String("compile", "", "use `exe` as the cmd/compile binary")
+	flagAssembler      = flag.String("asm", "", "use `exe` as the cmd/asm binary")
 	flagCompilerFlags  = flag.String("compileflags", "", "additional `flags` to pass to compile")
 	flagLinker         = flag.String("link", "", "use `exe` as the cmd/link binary")
 	flagLinkerFlags    = flag.String("linkflags", "", "additional `flags` to pass to link")
@@ -115,6 +119,7 @@
 	flagMemprofilerate = flag.Int64("memprofilerate", -1, "set memory profile `rate`")
 	flagPackage        = flag.String("pkg", "", "if set, benchmark the package at path `pkg`")
 	flagShort          = flag.Bool("short", false, "skip long-running benchmarks")
+	flagTrace          = flag.Bool("trace", false, "debug tracing of builds")
 )
 
 type test struct {
@@ -177,6 +182,10 @@
 			is6g = true
 		}
 	}
+	assembler = *flagAssembler
+	if assembler == "" {
+		_, assembler = toolPath("asm")
+	}
 
 	linker = *flagLinker
 	if linker == "" && !is6g { // TODO: Support 6l
@@ -237,8 +246,10 @@
 }
 
 type Pkg struct {
-	Dir     string
-	GoFiles []string
+	ImportPath string
+	Dir        string
+	GoFiles    []string
+	SFiles     []string
 }
 
 func goList(dir string) (*Pkg, error) {
@@ -336,8 +347,30 @@
 		return err
 	}
 
-	args := []string{"-o", "_compilebench_.o"}
+	// If this package has assembly files, we'll need to pass a symabis
+	// file to the compiler; call a helper to invoke the assembler
+	// to do that.
+	var symAbisFile string
+	var asmIncFile string
+	if len(pkg.SFiles) != 0 {
+		symAbisFile = filepath.Join(pkg.Dir, "symabis")
+		asmIncFile = filepath.Join(pkg.Dir, "go_asm.h")
+		content := "\n"
+		if err := os.WriteFile(asmIncFile, []byte(content), 0666); err != nil {
+			return fmt.Errorf("os.WriteFile(%s) failed: %v", asmIncFile, err)
+		}
+		defer os.Remove(symAbisFile)
+		defer os.Remove(asmIncFile)
+		if err := genSymAbisFile(pkg, symAbisFile, pkg.Dir); err != nil {
+			return err
+		}
+	}
+
+	args := []string{"-o", "_compilebench_.o", "-p", pkg.ImportPath}
 	args = append(args, strings.Fields(*flagCompilerFlags)...)
+	if symAbisFile != "" {
+		args = append(args, "-symabis", symAbisFile)
+	}
 	args = append(args, pkg.GoFiles...)
 	if err := runBuildCmd(name, count, pkg.Dir, compiler, args); err != nil {
 		return err
@@ -428,6 +461,10 @@
 			preArgs = append(preArgs, "-cpuprofile", "_compilebench_.cpuprof")
 		}
 	}
+	if *flagTrace {
+		fmt.Fprintf(os.Stderr, "running: %s %+v\n",
+			tool, append(preArgs, args...))
+	}
 	cmd := exec.Command(tool, append(preArgs, args...)...)
 	cmd.Dir = dir
 	cmd.Stdout = os.Stderr
@@ -510,3 +547,34 @@
 
 	return nil
 }
+
+// genSymAbisFile runs the assembler on the target packge asm files
+// with "-gensymabis" to produce a symabis file that will feed into
+// the Go source compilation. This is fairly hacky in that if the
+// asm invocation convenion changes it will need to be updated
+// (hopefully that will not be needed too frequently).
+func genSymAbisFile(pkg *Pkg, symAbisFile, incdir string) error {
+	args := []string{"-gensymabis", "-o", symAbisFile,
+		"-p", pkg.ImportPath,
+		"-I", filepath.Join(goroot, "pkg", "include"),
+		"-I", incdir,
+		"-D", "GOOS_" + runtime.GOOS,
+		"-D", "GOARCH_" + runtime.GOARCH}
+	if pkg.ImportPath == "reflect" {
+		args = append(args, "-compiling-runtime")
+	}
+	args = append(args, pkg.SFiles...)
+	if *flagTrace {
+		fmt.Fprintf(os.Stderr, "running: %s %+v\n",
+			assembler, args)
+	}
+	cmd := exec.Command(assembler, args...)
+	cmd.Dir = pkg.Dir
+	cmd.Stdout = os.Stderr
+	cmd.Stderr = os.Stderr
+	err := cmd.Run()
+	if err != nil {
+		return fmt.Errorf("assembling to produce symabis file: %v", err)
+	}
+	return nil
+}