1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 //go:generate go run mkbuiltin.go
12 "cmd/compile/internal/ssa"
27 var imported_unsafe bool
42 // These can be specified with the -d flag, as in "-d nil"
43 // to set the debug_checknil variable. In general the list passed
44 // to -d can be comma-separated.
45 var debugtab = []struct {
49 {"append", &Debug_append}, // print information about append compilation
50 {"closure", &Debug_closure}, // print information about closure compilation
51 {"disablenil", &disable_checknil}, // disable nil checks
52 {"gcprog", &Debug_gcprog}, // print dump of GC programs
53 {"nil", &Debug_checknil}, // print information about nil checks
54 {"panic", &Debug_panic}, // do not hide any compiler panic
55 {"slice", &Debug_slice}, // print information about slice compilation
56 {"typeassert", &Debug_typeassert}, // print information about type assertion inlining
57 {"wb", &Debug_wb}, // print information about write barriers
58 {"export", &Debug_export}, // print export data
62 fmt.Printf("usage: compile [options] file.go...\n")
68 if Debug_panic == 0 && nsavederrors+nerrors > 0 {
69 // If we've already complained about things
70 // in the program, don't bother complaining
71 // about a panic too; let the user clean up
72 // the code and try again.
73 if err := recover(); err != nil {
88 fmt.Printf("compile version %s%s%s\n", obj.Version, sep, p)
92 // supportsDynlink reports whether or not the code generator for the given
93 // architecture supports the -shared and -dynlink flags.
94 func supportsDynlink(arch *sys.Arch) bool {
95 return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.S390X)
98 // timing data for compiler phases
102 // Main parses flags and Go source files specified in the command-line
103 // arguments, type-checks the parsed Go package, compiles functions to machine
104 // code, and finally writes the compiled package definition to disk.
106 timings.Start("fe", "init")
110 Ctxt = obj.Linknew(Thearch.LinkArch)
111 Ctxt.DiagFunc = yyerror
112 Ctxt.Bso = bufio.NewWriter(os.Stdout)
115 localpkg.Prefix = "\"\""
117 // pseudo-package, for scoping
118 builtinpkg = mkpkg("go.builtin")
119 builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin
121 // pseudo-package, accessed by import "unsafe"
122 unsafepkg = mkpkg("unsafe")
123 unsafepkg.Name = "unsafe"
125 // real package, referred to by generated runtime calls
126 Runtimepkg = mkpkg("runtime")
127 Runtimepkg.Name = "runtime"
129 // pseudo-packages used in symbol tables
130 itabpkg = mkpkg("go.itab")
131 itabpkg.Name = "go.itab"
132 itabpkg.Prefix = "go.itab" // not go%2eitab
134 itablinkpkg = mkpkg("go.itablink")
135 itablinkpkg.Name = "go.itablink"
136 itablinkpkg.Prefix = "go.itablink" // not go%2eitablink
138 trackpkg = mkpkg("go.track")
139 trackpkg.Name = "go.track"
140 trackpkg.Prefix = "go.track" // not go%2etrack
142 typepkg = mkpkg("type")
143 typepkg.Name = "type"
145 // pseudo-package used for map zero values
146 mappkg = mkpkg("go.map")
147 mappkg.Name = "go.map"
148 mappkg.Prefix = "go.map"
150 Nacl = obj.GOOS == "nacl"
152 flag_largemodel = true
155 flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
156 obj.Flagcount("%", "debug non-static initializers", &Debug['%'])
157 obj.Flagcount("B", "disable bounds checking", &Debug['B'])
158 flag.StringVar(&localimport, "D", "", "set relative `path` for local imports")
159 obj.Flagcount("E", "debug symbol export", &Debug['E'])
160 obj.Flagfn1("I", "add `directory` to import search path", addidir)
161 obj.Flagcount("K", "debug missing line numbers", &Debug['K'])
162 obj.Flagcount("N", "disable optimizations", &Debug['N'])
163 obj.Flagcount("S", "print assembly listing", &Debug['S'])
164 obj.Flagfn0("V", "print compiler version", doversion)
165 obj.Flagcount("W", "debug parse tree after type checking", &Debug['W'])
166 flag.StringVar(&asmhdr, "asmhdr", "", "write assembly header to `file`")
167 flag.StringVar(&buildid, "buildid", "", "record `id` as the build id in the export metadata")
168 flag.BoolVar(&pure_go, "complete", false, "compiling complete package (no C or assembly)")
169 flag.StringVar(&debugstr, "d", "", "print debug information about items in `list`")
170 obj.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
171 obj.Flagcount("f", "debug stack frames", &Debug['f'])
172 obj.Flagcount("h", "halt on error", &Debug['h'])
173 obj.Flagcount("i", "debug line number stack", &Debug['i'])
174 obj.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
175 flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
176 obj.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
177 obj.Flagcount("l", "disable inlining", &Debug['l'])
178 flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`")
179 obj.Flagcount("live", "debug liveness analysis", &debuglive)
180 obj.Flagcount("m", "print optimization decisions", &Debug['m'])
181 flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
182 flag.BoolVar(&nolocalimports, "nolocalimports", false, "reject local (relative) imports")
183 flag.StringVar(&outfile, "o", "", "write output to `file`")
184 flag.StringVar(&myimportpath, "p", "", "set expected package import `path`")
185 flag.BoolVar(&writearchive, "pack", false, "write package file instead of object file")
186 obj.Flagcount("r", "debug generated wrappers", &Debug['r'])
187 flag.BoolVar(&flag_race, "race", false, "enable race detector")
188 obj.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
189 flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
190 flag.BoolVar(&safemode, "u", false, "reject unsafe code")
191 obj.Flagcount("v", "increase debug verbosity", &Debug['v'])
192 obj.Flagcount("w", "debug type checking", &Debug['w'])
193 flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier")
195 var flag_dynlink bool
196 if supportsDynlink(Thearch.LinkArch.Arch) {
197 flag.BoolVar(&flag_shared, "shared", false, "generate code that can be linked into a shared library")
198 flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
200 if Thearch.LinkArch.Family == sys.AMD64 {
201 flag.BoolVar(&flag_largemodel, "largemodel", false, "generate code that assumes a large memory model")
203 flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`")
204 flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`")
205 flag.Int64Var(&memprofilerate, "memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
206 flag.StringVar(&traceprofile, "traceprofile", "", "write an execution trace to `file`")
207 flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
210 Ctxt.Flag_shared = flag_dynlink || flag_shared
211 Ctxt.Flag_dynlink = flag_dynlink
212 Ctxt.Flag_optimize = Debug['N'] == 0
214 Ctxt.Debugasm = int32(Debug['S'])
215 Ctxt.Debugvlog = int32(Debug['v'])
223 if i := strings.LastIndex(p, "/"); i >= 0 {
226 if runtime.GOOS == "windows" {
227 if i := strings.LastIndex(p, `\`); i >= 0 {
231 if i := strings.LastIndex(p, "."); i >= 0 {
244 racepkg = mkpkg("runtime/race")
245 racepkg.Name = "race"
248 msanpkg = mkpkg("runtime/msan")
249 msanpkg.Name = "msan"
251 if flag_race && flag_msan {
252 log.Fatal("cannot use both -race and -msan")
253 } else if flag_race || flag_msan {
260 for _, name := range strings.Split(debugstr, ",") {
266 if i := strings.Index(name, "="); i >= 0 {
268 val, err = strconv.Atoi(name[i+1:])
270 log.Fatalf("invalid debug value %v", name)
273 } else if i := strings.Index(name, ":"); i >= 0 {
274 valstring = name[i+1:]
277 for _, t := range debugtab {
285 // special case for ssa for now
286 if strings.HasPrefix(name, "ssa/") {
287 // expect form ssa/phase/flag
288 // e.g. -d=ssa/generic_cse/time
289 // _ in phase name also matches space
291 flag := "debug" // default flag is debug
292 if i := strings.Index(phase, "/"); i >= 0 {
296 err := ssa.PhaseOption(phase, flag, val, valstring)
302 log.Fatalf("unknown debug key -d %s\n", name)
306 // enable inlining. for now:
307 // default: inlining on. (debug['l'] == 1)
308 // -l: inlining off (debug['l'] == 0)
309 // -ll, -lll: inlining on again, with extra debugging (debug['l'] > 1)
311 Debug['l'] = 1 - Debug['l']
314 Widthint = Thearch.LinkArch.IntSize
315 Widthptr = Thearch.LinkArch.PtrSize
316 Widthreg = Thearch.LinkArch.RegSize
324 timings.Start("fe", "loadsys")
327 timings.Start("fe", "parse")
328 lines := parseFiles(flag.Args())
330 timings.AddEvent(int64(lines), "lines")
340 // Process top-level declarations in phases.
342 // Phase 1: const, type, and names and types of funcs.
343 // This will gather all the information about types
344 // and methods but doesn't depend on any of it.
347 // Don't use range--typecheck can add closures to xtop.
348 timings.Start("fe", "typecheck", "top1")
349 for i := 0; i < len(xtop); i++ {
350 if xtop[i].Op != ODCL && xtop[i].Op != OAS && xtop[i].Op != OAS2 {
351 xtop[i] = typecheck(xtop[i], Etop)
355 // Phase 2: Variable assignments.
356 // To check interface assignments, depends on phase 1.
358 // Don't use range--typecheck can add closures to xtop.
359 timings.Start("fe", "typecheck", "top2")
360 for i := 0; i < len(xtop); i++ {
361 if xtop[i].Op == ODCL || xtop[i].Op == OAS || xtop[i].Op == OAS2 {
362 xtop[i] = typecheck(xtop[i], Etop)
367 // Phase 3: Type check function bodies.
368 // Don't use range--typecheck can add closures to xtop.
369 timings.Start("fe", "typecheck", "func")
371 for i := 0; i < len(xtop); i++ {
372 if xtop[i].Op == ODCLFUNC || xtop[i].Op == OCLOSURE {
376 typecheckslice(Curfn.Nbody.Slice(), Etop)
379 Curfn.Nbody.Set(nil) // type errors; do not compile
384 timings.AddEvent(fcount, "funcs")
386 // Phase 4: Decide how to capture closed variables.
387 // This needs to run before escape analysis,
388 // because variables captured by value do not escape.
389 timings.Start("fe", "capturevars")
390 for _, n := range xtop {
391 if n.Op == ODCLFUNC && n.Func.Closure != nil {
399 if nsavederrors+nerrors != 0 {
404 timings.Start("fe", "inlining")
406 // Typecheck imported function bodies if debug['l'] > 1,
407 // otherwise lazily when used or re-exported.
408 for _, n := range importlist {
409 if n.Func.Inl.Len() != 0 {
415 if nsavederrors+nerrors != 0 {
421 // Find functions that can be inlined and clone them before walk expands them.
422 visitBottomUp(xtop, func(list []*Node, recursive bool) {
423 for _, n := range list {
428 fmt.Printf("%v: cannot inline %v: recursive\n", n.Line(), n.Func.Nname)
436 // Phase 6: Escape analysis.
437 // Required for moving heap allocations onto stack,
438 // which in turn is required by the closure implementation,
439 // which stores the addresses of stack variables into the closure.
440 // If the closure does not escape, it needs to be on the stack
441 // or else the stack copier will not update it.
442 // Large values are also moved off stack in escape analysis;
443 // because large values may contain pointers, it must happen early.
444 timings.Start("fe", "escapes")
447 // Phase 7: Transform closure bodies to properly reference captured variables.
448 // This needs to happen before walk, because closures must be transformed
449 // before walk reaches a call of a closure.
450 timings.Start("fe", "xclosures")
451 for _, n := range xtop {
452 if n.Op == ODCLFUNC && n.Func.Closure != nil {
460 // Phase 8: Compile top level functions.
461 // Don't use range--walk can add functions to xtop.
462 timings.Start("be", "compilefuncs")
464 for i := 0; i < len(xtop); i++ {
465 if xtop[i].Op == ODCLFUNC {
470 timings.AddEvent(fcount, "funcs")
472 if nsavederrors+nerrors == 0 {
476 if compiling_runtime {
477 checknowritebarrierrec()
480 // Phase 9: Check external declarations.
481 timings.Start("be", "externaldcls")
482 for i, n := range externdcl {
484 externdcl[i] = typecheck(externdcl[i], Erv)
488 if nerrors+nsavederrors != 0 {
492 // Write object data to disk.
493 timings.Start("be", "dumpobj")
499 if nerrors+nsavederrors != 0 {
507 if err := writebench(benchfile); err != nil {
508 log.Fatalf("cannot write benchmark data: %v", err)
513 func writebench(filename string) error {
514 f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
520 fmt.Fprintln(&buf, "commit:", obj.Version)
521 fmt.Fprintln(&buf, "goos:", runtime.GOOS)
522 fmt.Fprintln(&buf, "goarch:", runtime.GOARCH)
523 timings.Write(&buf, "BenchmarkCompile:"+myimportpath+":")
525 n, err := f.Write(buf.Bytes())
536 var importMap = map[string]string{}
538 func addImportMap(s string) {
539 if strings.Count(s, "=") != 1 {
540 log.Fatal("-importmap argument must be of the form source=actual")
542 i := strings.Index(s, "=")
543 source, actual := s[:i], s[i+1:]
544 if source == "" || actual == "" {
545 log.Fatal("-importmap argument must be of the form source=actual; source and actual must be non-empty")
547 importMap[source] = actual
551 nsavederrors += nerrors
555 func arsize(b *bufio.Reader, name string) int {
556 var buf [ArhdrSize]byte
557 if _, err := io.ReadFull(b, buf[:]); err != nil {
560 aname := strings.Trim(string(buf[0:16]), " ")
561 if !strings.HasPrefix(aname, name) {
564 asize := strings.Trim(string(buf[48:58]), " ")
565 i, _ := strconv.Atoi(asize)
569 func skiptopkgdef(b *bufio.Reader) bool {
571 p, err := b.ReadString('\n')
573 log.Fatalf("reading input: %v", err)
575 if p != "!<arch>\n" {
579 // package export block should be first
580 sz := arsize(b, "__.PKGDEF")
586 func addidir(dir string) {
588 idirs = append(idirs, dir)
592 func isDriveLetter(b byte) bool {
593 return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z'
596 // is this path a local name? begins with ./ or ../ or /
597 func islocalname(name string) bool {
598 return strings.HasPrefix(name, "/") ||
599 runtime.GOOS == "windows" && len(name) >= 3 && isDriveLetter(name[0]) && name[1] == ':' && name[2] == '/' ||
600 strings.HasPrefix(name, "./") || name == "." ||
601 strings.HasPrefix(name, "../") || name == ".."
604 func findpkg(name string) (file string, ok bool) {
605 if islocalname(name) {
606 if safemode || nolocalimports {
610 // try .a before .6. important for building libraries:
611 // if there is an array.6 in the array.a library,
612 // want to find all of array.a, not just array.6.
613 file = fmt.Sprintf("%s.a", name)
614 if _, err := os.Stat(file); err == nil {
617 file = fmt.Sprintf("%s.o", name)
618 if _, err := os.Stat(file); err == nil {
624 // local imports should be canonicalized already.
625 // don't want to see "encoding/../encoding/base64"
626 // as different from "encoding/base64".
627 if q := path.Clean(name); q != name {
628 yyerror("non-canonical import path %q (should be %q)", name, q)
632 for _, dir := range idirs {
633 file = fmt.Sprintf("%s/%s.a", dir, name)
634 if _, err := os.Stat(file); err == nil {
637 file = fmt.Sprintf("%s/%s.o", dir, name)
638 if _, err := os.Stat(file); err == nil {
643 if obj.GOROOT != "" {
646 if flag_installsuffix != "" {
648 suffix = flag_installsuffix
649 } else if flag_race {
652 } else if flag_msan {
657 file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", obj.GOROOT, obj.GOOS, obj.GOARCH, suffixsep, suffix, name)
658 if _, err := os.Stat(file); err == nil {
661 file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", obj.GOROOT, obj.GOOS, obj.GOARCH, suffixsep, suffix, name)
662 if _, err := os.Stat(file); err == nil {
670 // loadsys loads the definitions for the low-level runtime functions,
671 // so that the compiler can generate calls to them,
672 // but does not make them visible to user code.
677 importpkg = Runtimepkg
681 typs := runtimeTypes()
682 for _, d := range runtimeDecls {
683 sym := Pkglookup(d.name, importpkg)
687 importsym(sym, ONAME)
688 n := newfuncname(sym)
694 Fatalf("unhandled declaration tag %v", d.tag)
703 func importfile(f *Val, indent []byte) {
704 if importpkg != nil {
705 Fatalf("importpkg not nil")
708 path_, ok := f.U.(string)
710 yyerror("import statement not a string")
715 yyerror("import path is empty")
719 if isbadimport(path_) {
723 // The package name main is no longer reserved,
724 // but we reserve the import path "main" to identify
725 // the main package, just as we reserve the import
726 // path "math" to identify the standard math package.
728 yyerror("cannot import \"main\"")
732 if myimportpath != "" && path_ == myimportpath {
733 yyerror("import %q while compiling that package (import cycle)", path_)
737 if mapped, ok := importMap[path_]; ok {
741 if path_ == "unsafe" {
743 yyerror("cannot import package unsafe")
747 importpkg = unsafepkg
748 imported_unsafe = true
752 if islocalname(path_) {
754 yyerror("import path cannot be absolute path")
758 prefix := Ctxt.Pathname
759 if localimport != "" {
762 path_ = path.Join(prefix, path_)
764 if isbadimport(path_) {
769 file, found := findpkg(path_)
771 yyerror("can't find import: %q", path_)
775 importpkg = mkpkg(path_)
777 if importpkg.Imported {
781 importpkg.Imported = true
783 impf, err := os.Open(file)
785 yyerror("can't open import: %q: %v", path_, err)
789 imp := bufio.NewReader(impf)
791 const pkgSuffix = ".a"
792 if strings.HasSuffix(file, pkgSuffix) {
793 if !skiptopkgdef(imp) {
794 yyerror("import %s: not a package file", file)
799 // check object header
800 p, err := imp.ReadString('\n')
802 log.Fatalf("reading input: %v", err)
808 if p != "empty archive" {
809 if !strings.HasPrefix(p, "go object ") {
810 yyerror("import %s: not a go object file: %s", file, p)
814 q := fmt.Sprintf("%s %s %s %s", obj.GOOS, obj.GOARCH, obj.Version, obj.Expstring())
816 yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q)
821 // process header lines
824 p, err = imp.ReadString('\n')
826 log.Fatalf("reading input: %v", err)
829 break // header ends with blank line
831 if strings.HasPrefix(p, "safe") {
833 break // ok to ignore rest
836 if safemode && !safe {
837 yyerror("cannot import unsafe package %q", importpkg.Path)
840 // assume files move (get installed) so don't record the full path
841 // (e.g., for file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a")
842 Ctxt.AddImport(file[len(file)-len(path_)-len(pkgSuffix):])
844 // In the importfile, if we find:
845 // $$\n (textual format): not supported anymore
846 // $$B\n (binary format) : import directly, then feed the lexer a dummy statement
851 c, err = imp.ReadByte()
856 c, err = imp.ReadByte()
857 if c == '$' || err != nil {
863 // get character after $$
865 c, _ = imp.ReadByte()
870 yyerror("cannot import %s: old export format no longer supported (recompile library)", path_)
873 if Debug_export != 0 {
874 fmt.Printf("importing %s (%s)\n", path_, file)
876 imp.ReadByte() // skip \n after $$B
880 yyerror("no import in %q", path_)
885 func pkgnotused(lineno src.XPos, path string, name string) {
886 // If the package was imported with a name other than the final
887 // import path element, show it explicitly in the error message.
888 // Note that this handles both renamed imports and imports of
889 // packages containing unconventional package declarations.
890 // Note that this uses / always, even on Windows, because Go import
891 // paths always use forward slashes.
893 if i := strings.LastIndex(elem, "/"); i >= 0 {
896 if name == "" || elem == name {
897 yyerrorl(lineno, "imported and not used: %q", path)
899 yyerrorl(lineno, "imported and not used: %q as %s", path, name)
903 func mkpackage(pkgname string) {
904 if localpkg.Name == "" {
906 yyerror("invalid package name _")
908 localpkg.Name = pkgname
910 if pkgname != localpkg.Name {
911 yyerror("package %s; expected %s", pkgname, localpkg.Name)
916 func clearImports() {
917 for _, s := range localpkg.Syms {
921 if s.Def.Op == OPACK {
922 // throw away top-level package name leftover
923 // from previous file.
924 // leave s->block set to cause redeclaration
925 // errors if a conflicting top-level name is
926 // introduced by a different file.
927 if !s.Def.Used && nsyntaxerrors == 0 {
928 pkgnotused(s.Def.Pos, s.Def.Name.Pkg.Path, s.Name)
934 if s.Def.Sym != s && s.Flags&SymAlias == 0 {
935 // throw away top-level name left over
936 // from previous import . "x"
937 if s.Def.Name != nil && s.Def.Name.Pack != nil && !s.Def.Name.Pack.Used && nsyntaxerrors == 0 {
938 pkgnotused(s.Def.Name.Pack.Pos, s.Def.Name.Pack.Name.Pkg.Path, "")
939 s.Def.Name.Pack.Used = true