main.go raw
1 // mxssadump exercises the mxssa builder on a real package.
2 // It loads a package via the moxie loader, runs the native type checker (B1),
3 // then builds the mxssa IR (B2) and prints a summary.
4 //
5 // Usage: mxssadump <import-path|.>
6 package main
7
8 import (
9 "fmt"
10 "go/token"
11 "go/types"
12 "os"
13 "runtime"
14 "sort"
15 "strings"
16
17 "moxie/compileopts"
18 "moxie/goenv"
19 "moxie/loader"
20 "moxie/mxssa"
21 "moxie/syntax"
22 "moxie/typecheck"
23 "moxie/typecheck/bridge"
24 )
25
26 func main() {
27 if len(os.Args) < 2 {
28 fmt.Fprintln(os.Stderr, "usage: mxssadump <import-path|.>")
29 os.Exit(1)
30 }
31 target := os.Args[1]
32
33 opts := &compileopts.Options{GOOS: "linux", GOARCH: "amd64"}
34 cfg, err := newConfig(opts)
35 if err != nil {
36 fatalf("config: %v", err)
37 }
38
39 typeCfg := types.Config{Error: func(e error) {}}
40 prog, err := loader.Load(cfg, target, typeCfg)
41 if err != nil {
42 fatalf("load: %v", err)
43 }
44 prog.EnableSyntaxFiles()
45 if err := prog.Parse(); err != nil {
46 if !isMainNameError(err.Error()) {
47 fatalf("parse: %v", err)
48 }
49 }
50
51 mainPkg := prog.MainPkg()
52 if mainPkg == nil || len(mainPkg.SyntaxFiles) == 0 {
53 fatalf("no syntax files for %s", target)
54 }
55
56 // Build bridge importer from the go/types package graph.
57 pkgMap := make(map[string]*types.Package, len(prog.Packages))
58 for path, p := range prog.Packages {
59 if p.Pkg != nil {
60 pkgMap[path] = p.Pkg
61 }
62 }
63 imp := bridge.New(pkgMap)
64
65 // Run the native checker (B1).
66 tcPkg, _, err := typecheck.Check(mainPkg.ImportPath, mainPkg.SyntaxFiles, imp)
67 if err != nil {
68 fmt.Fprintf(os.Stderr, "warn: typecheck: %v\n", err)
69 }
70
71 // Build the mxssa IR (B2).
72 fset := token.NewFileSet()
73 ssaProg := mxssa.NewProgram(fset)
74
75 if tcPkg == nil {
76 fatalf("typecheck returned nil package")
77 }
78
79 // Collect typecheck.Info from the checker.
80 _, info, _ := typecheck.Check(mainPkg.ImportPath, mainPkg.SyntaxFiles, imp)
81
82 ssaPkg := ssaProg.CreatePackage(tcPkg, mainPkg.SyntaxFiles, info)
83
84 // Print summary.
85 fmt.Printf("package %s\n", mainPkg.ImportPath)
86 fmt.Printf(" syntax files: %d\n", len(mainPkg.SyntaxFiles))
87 fmt.Printf(" ssa members: %d\n", len(ssaPkg.Members))
88
89 var funcs, globals, types_, consts int
90 var funcNames []string
91 for name, m := range ssaPkg.Members {
92 switch m.(type) {
93 case *mxssa.Function:
94 funcs++
95 funcNames = append(funcNames, name)
96 case *mxssa.Global:
97 globals++
98 case *mxssa.Type_:
99 types_++
100 case *mxssa.NamedConst:
101 consts++
102 }
103 }
104 sort.Strings(funcNames)
105 fmt.Printf(" functions: %d\n", funcs)
106 fmt.Printf(" globals: %d\n", globals)
107 fmt.Printf(" types: %d\n", types_)
108 fmt.Printf(" consts: %d\n", consts)
109
110 // Print function block counts.
111 fmt.Println("\nfunctions:")
112 for _, name := range funcNames {
113 fn := ssaPkg.Members[name].(*mxssa.Function)
114 fmt.Printf(" %-30s blocks=%d params=%d\n", name, len(fn.Blocks), len(fn.Params))
115 }
116 }
117
118 func fatalf(format string, args ...interface{}) {
119 fmt.Fprintf(os.Stderr, "mxssadump: "+format+"\n", args...)
120 os.Exit(1)
121 }
122
123 func newConfig(options *compileopts.Options) (*compileopts.Config, error) {
124 spec, err := compileopts.LoadTarget(options)
125 if err != nil {
126 return nil, err
127 }
128 _, gorootMinor, err := goenv.GetGorootVersion()
129 if err != nil {
130 return nil, err
131 }
132 _, buildMinor, _, err := goenv.Parse(runtime.Version())
133 if err != nil {
134 return nil, err
135 }
136 if buildMinor < gorootMinor {
137 return nil, fmt.Errorf("go toolchain mismatch: built with %s, running %d.%d",
138 runtime.Version(), 1, gorootMinor)
139 }
140 return &compileopts.Config{
141 Options: options,
142 Target: spec,
143 GoMinorVersion: gorootMinor,
144 TestConfig: options.TestConfig,
145 }, nil
146 }
147
148 func isMainNameError(msg string) bool {
149 return strings.Contains(msg, "expected main package to have name")
150 }
151
152 var _ []*syntax.File
153