diff --git a/compiler/compiler.go b/compiler/compiler.go index 77300291..86d51a9e 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -28,10 +28,17 @@ func init() { llvm.InitializeAllAsmPrinters() } +// Configure the compiler. +type Config struct { + Triple string // LLVM target triple, e.g. x86_64-unknown-linux-gnu (empty string means default) + DumpSSA bool // dump Go SSA, for compiler debugging + Debug bool // add debug symbols for gdb + RootDir string // GOROOT for TinyGo + BuildTags []string // build tags for TinyGo (empty means {runtime.GOOS/runtime.GOARCH}) +} + type Compiler struct { - dumpSSA bool - debug bool - triple string + Config mod llvm.Module ctx llvm.Context builder llvm.Builder @@ -75,24 +82,28 @@ type Phi struct { llvm llvm.Value } -func NewCompiler(pkgName, triple string, dumpSSA bool) (*Compiler, error) { +func NewCompiler(pkgName string, config Config) (*Compiler, error) { + if config.Triple == "" { + config.Triple = llvm.DefaultTargetTriple() + } + if len(config.BuildTags) == 0 { + config.BuildTags = []string{runtime.GOOS, runtime.GOARCH} + } c := &Compiler{ - dumpSSA: dumpSSA, - debug: true, // TODO: make configurable - triple: triple, + Config: config, difiles: make(map[string]llvm.Metadata), ditypes: make(map[string]llvm.Metadata), } - target, err := llvm.GetTargetFromTriple(triple) + target, err := llvm.GetTargetFromTriple(config.Triple) if err != nil { return nil, err } - c.machine = target.CreateTargetMachine(triple, "", "", llvm.CodeGenLevelDefault, llvm.RelocStatic, llvm.CodeModelDefault) + c.machine = target.CreateTargetMachine(config.Triple, "", "", llvm.CodeGenLevelDefault, llvm.RelocStatic, llvm.CodeModelDefault) c.targetData = c.machine.CreateTargetData() c.mod = llvm.NewModule(pkgName) - c.mod.SetTarget(triple) + c.mod.SetTarget(config.Triple) c.mod.SetDataLayout(c.targetData.String()) c.ctx = c.mod.Context() c.builder = c.ctx.NewBuilder() @@ -134,8 +145,8 @@ func (c *Compiler) Module() llvm.Module { return c.mod } -func (c *Compiler) Parse(mainPath, sourceDir string, buildTags []string) error { - tripleSplit := strings.Split(c.triple, "-") +func (c *Compiler) Parse(mainPath string) error { + tripleSplit := strings.Split(c.Triple, "-") config := loader.Config{ TypeChecker: types.Config{ @@ -148,12 +159,12 @@ func (c *Compiler) Parse(mainPath, sourceDir string, buildTags []string) error { Build: &build.Context{ GOARCH: tripleSplit[0], GOOS: tripleSplit[2], - GOROOT: sourceDir, + GOROOT: c.RootDir, GOPATH: runtime.GOROOT(), CgoEnabled: true, UseAllFiles: false, Compiler: "gc", // must be one of the recognized compilers - BuildTags: append([]string{"tgo"}, buildTags...), + BuildTags: append([]string{"tgo"}, c.BuildTags...), }, ParserMode: parser.ParseComments, AllowErrors: true, @@ -303,7 +314,7 @@ func (c *Compiler) Parse(mainPath, sourceDir string, buildTags []string) error { // continues at runtime). // This should only happen when it hits a function call or the end // of the block, ideally. - err := c.ir.Interpret(frame.fn.Blocks[0], c.dumpSSA) + err := c.ir.Interpret(frame.fn.Blocks[0], c.DumpSSA) if err != nil { return err } @@ -835,7 +846,7 @@ func (c *Compiler) parseFuncDecl(f *ir.Function) (*Frame, error) { frame.fn.LLVMFn = llvm.AddFunction(c.mod, name, fnType) } - if c.debug && f.Syntax() != nil && len(f.Blocks) != 0 { + if c.Debug && f.Syntax() != nil && len(f.Blocks) != 0 { // Create debug info file if needed. pos := c.ir.Program.Fset.Position(f.Syntax().Pos()) if _, ok := c.difiles[pos.Filename]; !ok { @@ -1165,14 +1176,14 @@ func (c *Compiler) getInterpretedValue(prefix string, value ir.Value) (llvm.Valu } func (c *Compiler) parseFunc(frame *Frame) error { - if c.dumpSSA { + if c.DumpSSA { fmt.Printf("\nfunc %s:\n", frame.fn.Function) } if !frame.fn.IsExported() { frame.fn.LLVMFn.SetLinkage(llvm.InternalLinkage) } - if c.debug { + if c.Debug { pos := c.ir.Program.Fset.Position(frame.fn.Pos()) c.builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), frame.difunc, llvm.Metadata{}) } @@ -1204,7 +1215,7 @@ func (c *Compiler) parseFunc(frame *Frame) error { frame.locals[param] = c.collapseFormalParam(llvmType, fields) // Add debug information to this parameter (if available) - if c.debug && frame.fn.Syntax() != nil { + if c.Debug && frame.fn.Syntax() != nil { pos := c.ir.Program.Fset.Position(frame.fn.Syntax().Pos()) dityp, err := c.getDIType(param.Type()) if err != nil { @@ -1311,7 +1322,7 @@ func (c *Compiler) parseFunc(frame *Frame) error { // Fill blocks with instructions. for _, block := range frame.fn.DomPreorder() { - if c.dumpSSA { + if c.DumpSSA { fmt.Printf("%s:\n", block.Comment) } c.builder.SetInsertPointAtEnd(frame.blocks[block]) @@ -1320,7 +1331,7 @@ func (c *Compiler) parseFunc(frame *Frame) error { if _, ok := instr.(*ssa.DebugRef); ok { continue } - if c.dumpSSA { + if c.DumpSSA { if val, ok := instr.(ssa.Value); ok && val.Name() != "" { fmt.Printf("\t%s = %s\n", val.Name(), val.String()) } else { @@ -1354,7 +1365,7 @@ func (c *Compiler) parseFunc(frame *Frame) error { } func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error { - if c.debug { + if c.Debug { pos := c.ir.Program.Fset.Position(instr.Pos()) c.builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), frame.difunc, llvm.Metadata{}) } diff --git a/main.go b/main.go index 635b4e57..2965bb08 100644 --- a/main.go +++ b/main.go @@ -9,7 +9,6 @@ import ( "os" "os/exec" "path/filepath" - "runtime" "strings" "github.com/aykevl/llvm/bindings/go/llvm" @@ -18,7 +17,14 @@ import ( // Helper function for Compiler object. func Compile(pkgName, outpath string, spec *TargetSpec, printIR, dumpSSA bool, printSizes string, action func(string) error) error { - c, err := compiler.NewCompiler(pkgName, spec.Triple, dumpSSA) + config := compiler.Config{ + Triple: spec.Triple, + Debug: true, // TODO: make configurable + DumpSSA: dumpSSA, + RootDir: sourceDir(), + BuildTags: spec.BuildTags, + } + c, err := compiler.NewCompiler(pkgName, config) if err != nil { return err } @@ -32,7 +38,7 @@ func Compile(pkgName, outpath string, spec *TargetSpec, printIR, dumpSSA bool, p fmt.Println(c.IR()) }() } - return c.Parse(pkgName, sourceDir(), spec.BuildTags) + return c.Parse(pkgName) }() if parseErr != nil { return parseErr @@ -190,11 +196,14 @@ func Flash(pkgName, target, port string, printIR, dumpSSA bool, printSizes strin // Run the specified package directly (using JIT or interpretation). func Run(pkgName string) error { - c, err := compiler.NewCompiler(pkgName, llvm.DefaultTargetTriple(), false) + config := compiler.Config{ + RootDir: sourceDir(), + } + c, err := compiler.NewCompiler(pkgName, config) if err != nil { return errors.New("compiler: " + err.Error()) } - err = c.Parse(pkgName, sourceDir(), []string{runtime.GOOS, runtime.GOARCH}) + err = c.Parse(pkgName) if err != nil { return errors.New("compiler: " + err.Error()) }