Commit 9741d83c authored by Josh Bleecher Snyder's avatar Josh Bleecher Snyder

cmd/asm, go/build: invoke cmd/asm only once per package

Prior to this CL, cmd/go invoked cmd/asm once
for every assembly file.
The exec and cmd/asm startup overhead dwarfed
the actual time spent assembling.
This CL adds support to cmd/asm to process
multiple input files and uses it in cmd/go.

This cuts 10% off the wall time for 'go build -a math'.

Fixes #15680

Change-Id: I12d2ee2c817207954961dc8f37b8f2b09f835550
Reviewed-on: https://go-review.googlesource.com/27636
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarRob Pike <r@golang.org>
parent 9d4623fe
......@@ -15,7 +15,7 @@ import (
var (
Debug = flag.Bool("debug", false, "dump instructions as they are parsed")
OutputFile = flag.String("o", "", "output file; default foo.6 for /a/b/c/foo.s on amd64")
OutputFile = flag.String("o", "", "output file; default foo.o for /a/b/c/foo.s as first argument")
PrintOut = flag.Bool("S", false, "print assembly and machine code")
TrimPath = flag.String("trimpath", "", "remove prefix from recorded source file paths")
Shared = flag.Bool("shared", false, "generate code that can be linked into a shared library")
......@@ -49,7 +49,7 @@ func (m *MultiFlag) Set(val string) error {
}
func Usage() {
fmt.Fprintf(os.Stderr, "usage: asm [options] file.s\n")
fmt.Fprintf(os.Stderr, "usage: asm [options] file.s ...\n")
fmt.Fprintf(os.Stderr, "Flags:\n")
flag.PrintDefaults()
os.Exit(2)
......@@ -58,12 +58,15 @@ func Usage() {
func Parse() {
flag.Usage = Usage
flag.Parse()
if flag.NArg() != 1 {
if flag.NArg() == 0 {
flag.Usage()
}
// Flag refinement.
if *OutputFile == "" {
if flag.NArg() != 1 {
flag.Usage()
}
input := filepath.Base(flag.Arg(0))
if strings.HasSuffix(input, ".s") {
input = input[:len(input)-2]
......
......@@ -54,22 +54,32 @@ func main() {
fmt.Fprintf(buf, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion())
fmt.Fprintf(buf, "!\n")
lexer := lex.NewLexer(flag.Arg(0), ctxt)
parser := asm.NewParser(ctxt, architecture, lexer)
diag := false
ctxt.DiagFunc = func(format string, args ...interface{}) {
diag = true
log.Printf(format, args...)
var ok, diag bool
var failedFile string
for _, f := range flag.Args() {
lexer := lex.NewLexer(f, ctxt)
parser := asm.NewParser(ctxt, architecture, lexer)
ctxt.DiagFunc = func(format string, args ...interface{}) {
diag = true
log.Printf(format, args...)
}
pList := obj.Linknewplist(ctxt)
pList.Firstpc, ok = parser.Parse()
if !ok {
failedFile = f
break
}
}
pList := obj.Linknewplist(ctxt)
var ok bool
pList.Firstpc, ok = parser.Parse()
if ok {
// reports errors to parser.Errorf
obj.Writeobjdirect(ctxt, buf)
}
if !ok || diag {
log.Printf("assembly of %s failed", flag.Arg(0))
if failedFile != "" {
log.Printf("assembly of %s failed", failedFile)
} else {
log.Print("assembly failed")
}
os.Remove(*flags.OutputFile)
os.Exit(1)
}
......
......@@ -1561,12 +1561,12 @@ func (b *builder) build(a *action) (err error) {
}
// Assemble .s files.
for _, file := range sfiles {
out := file[:len(file)-len(".s")] + ".o"
if err := buildToolchain.asm(b, a.p, obj, obj+out, file); err != nil {
if len(sfiles) > 0 {
ofiles, err := buildToolchain.asm(b, a.p, obj, sfiles)
if err != nil {
return err
}
objects = append(objects, out)
objects = append(objects, ofiles...)
}
// NOTE(rsc): On Windows, it is critically important that the
......@@ -2203,9 +2203,9 @@ type toolchain interface {
// cc runs the toolchain's C compiler in a directory on a C file
// to produce an output file.
cc(b *builder, p *Package, objdir, ofile, cfile string) error
// asm runs the assembler in a specific directory on a specific file
// to generate the named output file.
asm(b *builder, p *Package, obj, ofile, sfile string) error
// asm runs the assembler in a specific directory on specific files
// and returns a list of named output files.
asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error)
// pkgpath builds an appropriate path for a temporary package file.
pkgpath(basedir string, p *Package) string
// pack runs the archive packer in a specific directory to create
......@@ -2242,8 +2242,8 @@ func (noToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
return "", nil, noCompiler()
}
func (noToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
return noCompiler()
func (noToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) {
return nil, noCompiler()
}
func (noToolchain) pkgpath(basedir string, p *Package) string {
......@@ -2340,10 +2340,10 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
return ofile, output, err
}
func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
func (gcToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) {
// Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
inc := filepath.Join(goroot, "pkg", "include")
sfile = mkAbs(p.Dir, sfile)
ofile := obj + "asm.o"
args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags}
if p.ImportPath == "runtime" && goarch == "386" {
for _, arg := range buildAsmflags {
......@@ -2352,11 +2352,13 @@ func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
}
}
}
args = append(args, sfile)
for _, sfile := range sfiles {
args = append(args, mkAbs(p.Dir, sfile))
}
if err := b.run(p.Dir, p.ImportPath, nil, args...); err != nil {
return err
return nil, err
}
return nil
return []string{ofile}, nil
}
// toolVerify checks that the command line args writes the same output file
......@@ -2623,15 +2625,24 @@ func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmh
return ofile, output, err
}
func (tools gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
sfile = mkAbs(p.Dir, sfile)
defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath)
func (tools gccgoToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) {
var ofiles []string
for _, sfile := range sfiles {
ofile := obj + sfile[:len(sfile)-len(".s")] + ".o"
ofiles = append(ofiles, ofile)
sfile = mkAbs(p.Dir, sfile)
defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath)
}
defs = tools.maybePIC(defs)
defs = append(defs, b.gccArchArgs()...)
err := b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-xassembler-with-cpp", "-I", obj, "-c", "-o", ofile, defs, sfile)
if err != nil {
return nil, err
}
}
defs = tools.maybePIC(defs)
defs = append(defs, b.gccArchArgs()...)
return b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-xassembler-with-cpp", "-I", obj, "-c", "-o", ofile, defs, sfile)
return ofiles, nil
}
func (gccgoToolchain) pkgpath(basedir string, p *Package) string {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment