]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/asm, go/build: invoke cmd/asm only once per package
authorJosh Bleecher Snyder <josharian@gmail.com>
Wed, 18 May 2016 20:27:11 +0000 (13:27 -0700)
committerJosh Bleecher Snyder <josharian@gmail.com>
Wed, 24 Aug 2016 22:31:34 +0000 (22:31 +0000)
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: Rob Pike <r@golang.org>
src/cmd/asm/internal/flags/flags.go
src/cmd/asm/main.go
src/cmd/go/build.go

index 4557c2a7f9edf366eb59a3829da8b2ef33a53c05..bd90b82bf6aebf9e207ebbb128ea524ac76f8014 100644 (file)
@@ -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]
index c612583e6bcd1763e5c5b1ec774ba25d24bffb36..09597327281f326bc37c557d77f0f4a641fce67c 100644 (file)
@@ -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)
        }
index bb76465ce7292bde2a81042b1d33642bf03e5bfb..b5df9a22c44969e2860158d67d63e1fd6004f71b 100644 (file)
@@ -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 {