// translatePackage translates an *ssa.Package into an LLVM module, and returns // the translation unit information. func (u *unit) translatePackage(pkg *ssa.Package) { // Initialize global storage. for _, m := range pkg.Members { switch v := m.(type) { case *ssa.Global: llelemtyp := u.llvmtypes.ToLLVM(deref(v.Type())) global := llvm.AddGlobal(u.module.Module, llelemtyp, v.String()) global.SetInitializer(llvm.ConstNull(llelemtyp)) u.globals[v] = u.NewValue(global, v.Type()) } } // Define functions. // Sort if flag is set for deterministic behaviour (for debugging) functions := ssautil.AllFunctions(pkg.Prog) if !u.compiler.OrderedCompilation { for f, _ := range functions { u.defineFunction(f) } } else { fns := []*ssa.Function{} for f, _ := range functions { fns = append(fns, f) } sort.Sort(byName(fns)) for _, f := range fns { u.defineFunction(f) } } // Define remaining functions that were resolved during // runtime type mapping, but not defined. for f, _ := range u.undefinedFuncs { u.defineFunction(f) } }
// peers enumerates, for a given channel send (or receive) operation, // the set of possible receives (or sends) that correspond to it. // // TODO(adonovan): support reflect.{Select,Recv,Send}. // TODO(adonovan): permit the user to query based on a MakeChan (not send/recv), // or the implicit receive in "for v := range ch". // func peers(o *Oracle, qpos *QueryPos) (queryResult, error) { arrowPos := findArrow(qpos) if arrowPos == token.NoPos { return nil, fmt.Errorf("there is no send/receive here") } buildSSA(o) var queryOp chanOp // the originating send or receive operation var ops []chanOp // all sends/receives of opposite direction // Look at all send/receive instructions in the whole ssa.Program. // Build a list of those of same type to query. allFuncs := ssautil.AllFunctions(o.prog) for fn := range allFuncs { for _, b := range fn.Blocks { for _, instr := range b.Instrs { for _, op := range chanOps(instr) { ops = append(ops, op) if op.pos == arrowPos { queryOp = op // we found the query op } } } } } if queryOp.ch == nil { return nil, fmt.Errorf("ssa.Instruction for send/receive not found") } // Discard operations of wrong channel element type. // Build set of channel ssa.Values as query to pointer analysis. // We compare channels by element types, not channel types, to // ignore both directionality and type names. queryType := queryOp.ch.Type() queryElemType := queryType.Underlying().(*types.Chan).Elem() o.ptaConfig.AddQuery(queryOp.ch) i := 0 for _, op := range ops { if types.IsIdentical(op.ch.Type().Underlying().(*types.Chan).Elem(), queryElemType) { o.ptaConfig.AddQuery(op.ch) ops[i] = op i++ } } ops = ops[:i] // Run the pointer analysis. ptares := ptrAnalysis(o) // Combine the PT sets from all contexts. queryChanPts := pointer.PointsToCombined(ptares.Queries[queryOp.ch]) // Ascertain which make(chan) labels the query's channel can alias. var makes []token.Pos for _, label := range queryChanPts.Labels() { makes = append(makes, label.Pos()) } sort.Sort(byPos(makes)) // Ascertain which send/receive operations can alias the same make(chan) labels. var sends, receives []token.Pos for _, op := range ops { for _, ptr := range ptares.Queries[op.ch] { if ptr.PointsTo().Intersects(queryChanPts) { if op.dir == types.SendOnly { sends = append(sends, op.pos) } else { receives = append(receives, op.pos) } } } } sort.Sort(byPos(sends)) sort.Sort(byPos(receives)) return &peersResult{ queryPos: arrowPos, queryType: queryType, makes: makes, sends: sends, receives: receives, }, nil }
func TestStdlib(t *testing.T) { impctx := importer.Config{Build: &build.Default} // Load, parse and type-check the program. t0 := time.Now() imp := importer.New(&impctx) if _, _, err := imp.LoadInitialPackages(allPackages()); err != nil { t.Errorf("LoadInitialPackages failed: %s", err) return } t1 := time.Now() runtime.GC() var memstats runtime.MemStats runtime.ReadMemStats(&memstats) alloc := memstats.Alloc // Create SSA packages. prog := ssa.NewProgram(imp.Fset, ssa.SanityCheckFunctions) if err := prog.CreatePackages(imp); err != nil { t.Errorf("CreatePackages failed: %s", err) return } // Enable debug mode globally. for _, info := range imp.AllPackages() { prog.Package(info.Pkg).SetDebugMode(debugMode) } t2 := time.Now() // Build SSA IR... if it's safe. prog.BuildAll() t3 := time.Now() runtime.GC() runtime.ReadMemStats(&memstats) numPkgs := len(prog.AllPackages()) if want := 140; numPkgs < want { t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want) } // Dump some statistics. allFuncs := ssautil.AllFunctions(prog) var numInstrs int for fn := range allFuncs { for _, b := range fn.Blocks { numInstrs += len(b.Instrs) } } // determine line count var lineCount int imp.Fset.Iterate(func(f *token.File) bool { lineCount += f.LineCount() return true }) // NB: when benchmarking, don't forget to clear the debug + // sanity builder flags for better performance. t.Log("GOMAXPROCS: ", runtime.GOMAXPROCS(0)) t.Log("#Source lines: ", lineCount) t.Log("Load/parse/typecheck: ", t1.Sub(t0)) t.Log("SSA create: ", t2.Sub(t1)) t.Log("SSA build: ", t3.Sub(t2)) // SSA stats: t.Log("#Packages: ", numPkgs) t.Log("#Functions: ", len(allFuncs)) t.Log("#Instructions: ", numInstrs) t.Log("#MB: ", (memstats.Alloc-alloc)/1000000) }