compiler: refactor public interface
This commit merges NewCompiler and Compile into one simplifying the external interface. More importantly, it does away with the entire Compiler object so the public API becomes a lot smaller. The refactor is not complete: eventually, the compiler should just compile a single package without trying to load it first (that should be done by the builder package).
Этот коммит содержится в:
родитель
8ef921e028
коммит
c4fd19be99
3 изменённых файлов: 96 добавлений и 130 удалений
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/tinygo-org/tinygo/goenv"
|
"github.com/tinygo-org/tinygo/goenv"
|
||||||
"github.com/tinygo-org/tinygo/interp"
|
"github.com/tinygo-org/tinygo/interp"
|
||||||
"github.com/tinygo-org/tinygo/transform"
|
"github.com/tinygo-org/tinygo/transform"
|
||||||
|
"tinygo.org/x/go-llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Build performs a single package to executable Go build. It takes in a package
|
// Build performs a single package to executable Go build. It takes in a package
|
||||||
|
@ -26,34 +27,34 @@ import (
|
||||||
// The error value may be of type *MultiError. Callers will likely want to check
|
// The error value may be of type *MultiError. Callers will likely want to check
|
||||||
// for this case and print such errors individually.
|
// for this case and print such errors individually.
|
||||||
func Build(pkgName, outpath string, config *compileopts.Config, action func(string) error) error {
|
func Build(pkgName, outpath string, config *compileopts.Config, action func(string) error) error {
|
||||||
c, err := compiler.NewCompiler(pkgName, config)
|
// Compile Go code to IR.
|
||||||
|
machine, err := compiler.NewTargetMachine(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
mod, extraFiles, errs := compiler.Compile(pkgName, machine, config)
|
||||||
// Compile Go code to IR.
|
if errs != nil {
|
||||||
errs := c.Compile(pkgName)
|
|
||||||
if len(errs) != 0 {
|
|
||||||
return newMultiError(errs)
|
return newMultiError(errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Options.PrintIR {
|
if config.Options.PrintIR {
|
||||||
fmt.Println("; Generated LLVM IR:")
|
fmt.Println("; Generated LLVM IR:")
|
||||||
fmt.Println(c.IR())
|
fmt.Println(mod.String())
|
||||||
}
|
}
|
||||||
if err := c.Verify(); err != nil {
|
if err := llvm.VerifyModule(mod, llvm.PrintMessageAction); err != nil {
|
||||||
return errors.New("verification error after IR construction")
|
return errors.New("verification error after IR construction")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = interp.Run(c.Module(), config.DumpSSA())
|
err = interp.Run(mod, config.DumpSSA())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := c.Verify(); err != nil {
|
if err := llvm.VerifyModule(mod, llvm.PrintMessageAction); err != nil {
|
||||||
return errors.New("verification error after interpreting runtime.initAll")
|
return errors.New("verification error after interpreting runtime.initAll")
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.GOOS() != "darwin" {
|
if config.GOOS() != "darwin" {
|
||||||
transform.ApplyFunctionSections(c.Module()) // -ffunction-sections
|
transform.ApplyFunctionSections(mod) // -ffunction-sections
|
||||||
}
|
}
|
||||||
|
|
||||||
// Browsers cannot handle external functions that have type i64 because it
|
// Browsers cannot handle external functions that have type i64 because it
|
||||||
|
@ -62,7 +63,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
|
||||||
// stack-allocated values.
|
// stack-allocated values.
|
||||||
// Use -wasm-abi=generic to disable this behaviour.
|
// Use -wasm-abi=generic to disable this behaviour.
|
||||||
if config.Options.WasmAbi == "js" && strings.HasPrefix(config.Triple(), "wasm") {
|
if config.Options.WasmAbi == "js" && strings.HasPrefix(config.Triple(), "wasm") {
|
||||||
err := transform.ExternalInt64AsPtr(c.Module())
|
err := transform.ExternalInt64AsPtr(mod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -73,22 +74,22 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
|
||||||
errs = nil
|
errs = nil
|
||||||
switch config.Options.Opt {
|
switch config.Options.Opt {
|
||||||
case "none", "0":
|
case "none", "0":
|
||||||
errs = transform.Optimize(c.Module(), config, 0, 0, 0) // -O0
|
errs = transform.Optimize(mod, config, 0, 0, 0) // -O0
|
||||||
case "1":
|
case "1":
|
||||||
errs = transform.Optimize(c.Module(), config, 1, 0, 0) // -O1
|
errs = transform.Optimize(mod, config, 1, 0, 0) // -O1
|
||||||
case "2":
|
case "2":
|
||||||
errs = transform.Optimize(c.Module(), config, 2, 0, 225) // -O2
|
errs = transform.Optimize(mod, config, 2, 0, 225) // -O2
|
||||||
case "s":
|
case "s":
|
||||||
errs = transform.Optimize(c.Module(), config, 2, 1, 225) // -Os
|
errs = transform.Optimize(mod, config, 2, 1, 225) // -Os
|
||||||
case "z":
|
case "z":
|
||||||
errs = transform.Optimize(c.Module(), config, 2, 2, 5) // -Oz, default
|
errs = transform.Optimize(mod, config, 2, 2, 5) // -Oz, default
|
||||||
default:
|
default:
|
||||||
errs = []error{errors.New("unknown optimization level: -opt=" + config.Options.Opt)}
|
errs = []error{errors.New("unknown optimization level: -opt=" + config.Options.Opt)}
|
||||||
}
|
}
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
return newMultiError(errs)
|
return newMultiError(errs)
|
||||||
}
|
}
|
||||||
if err := c.Verify(); err != nil {
|
if err := llvm.VerifyModule(mod, llvm.PrintMessageAction); err != nil {
|
||||||
return errors.New("verification failure after LLVM optimization passes")
|
return errors.New("verification failure after LLVM optimization passes")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,8 +99,8 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
|
||||||
// pointers are flash and which are in RAM so that pointers can have a
|
// pointers are flash and which are in RAM so that pointers can have a
|
||||||
// correct address space parameter (address space 1 is for flash).
|
// correct address space parameter (address space 1 is for flash).
|
||||||
if strings.HasPrefix(config.Triple(), "avr") {
|
if strings.HasPrefix(config.Triple(), "avr") {
|
||||||
transform.NonConstGlobals(c.Module())
|
transform.NonConstGlobals(mod)
|
||||||
if err := c.Verify(); err != nil {
|
if err := llvm.VerifyModule(mod, llvm.PrintMessageAction); err != nil {
|
||||||
return errors.New("verification error after making all globals non-constant on AVR")
|
return errors.New("verification error after making all globals non-constant on AVR")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,11 +109,17 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
|
||||||
outext := filepath.Ext(outpath)
|
outext := filepath.Ext(outpath)
|
||||||
switch outext {
|
switch outext {
|
||||||
case ".o":
|
case ".o":
|
||||||
return c.EmitObject(outpath)
|
llvmBuf, err := machine.EmitToMemoryBuffer(mod, llvm.ObjectFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return ioutil.WriteFile(outpath, llvmBuf.Bytes(), 0666)
|
||||||
case ".bc":
|
case ".bc":
|
||||||
return c.EmitBitcode(outpath)
|
data := llvm.WriteBitcodeToMemoryBuffer(mod).Bytes()
|
||||||
|
return ioutil.WriteFile(outpath, data, 0666)
|
||||||
case ".ll":
|
case ".ll":
|
||||||
return c.EmitText(outpath)
|
data := []byte(mod.String())
|
||||||
|
return ioutil.WriteFile(outpath, data, 0666)
|
||||||
default:
|
default:
|
||||||
// Act as a compiler driver.
|
// Act as a compiler driver.
|
||||||
|
|
||||||
|
@ -125,7 +132,11 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
|
||||||
|
|
||||||
// Write the object file.
|
// Write the object file.
|
||||||
objfile := filepath.Join(dir, "main.o")
|
objfile := filepath.Join(dir, "main.o")
|
||||||
err = c.EmitObject(objfile)
|
llvmBuf, err := machine.EmitToMemoryBuffer(mod, llvm.ObjectFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = ioutil.WriteFile(objfile, llvmBuf.Bytes(), 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -167,16 +178,13 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile C files in packages.
|
// Compile C files in packages.
|
||||||
for i, pkg := range c.Packages() {
|
for i, file := range extraFiles {
|
||||||
for _, file := range pkg.CFiles {
|
outpath := filepath.Join(dir, "pkg"+strconv.Itoa(i)+"-"+filepath.Base(file)+".o")
|
||||||
path := filepath.Join(pkg.Package.Dir, file)
|
err := runCCompiler(config.Target.Compiler, append(config.CFlags(), "-c", "-o", outpath, file)...)
|
||||||
outpath := filepath.Join(dir, "pkg"+strconv.Itoa(i)+"-"+file+".o")
|
if err != nil {
|
||||||
err := runCCompiler(config.Target.Compiler, append(config.CFlags(), "-c", "-o", outpath, path)...)
|
return &commandError{"failed to build", file, err}
|
||||||
if err != nil {
|
|
||||||
return &commandError{"failed to build", path, err}
|
|
||||||
}
|
|
||||||
ldflags = append(ldflags, outpath)
|
|
||||||
}
|
}
|
||||||
|
ldflags = append(ldflags, outpath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link the object files together.
|
// Link the object files together.
|
||||||
|
|
|
@ -56,12 +56,6 @@ type compilerContext struct {
|
||||||
astComments map[string]*ast.CommentGroup
|
astComments map[string]*ast.CommentGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
type Compiler struct {
|
|
||||||
compilerContext
|
|
||||||
builder llvm.Builder
|
|
||||||
initFuncs []llvm.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
// builder contains all information relevant to build a single function.
|
// builder contains all information relevant to build a single function.
|
||||||
type builder struct {
|
type builder struct {
|
||||||
*compilerContext
|
*compilerContext
|
||||||
|
@ -88,28 +82,40 @@ type Phi struct {
|
||||||
llvm llvm.Value
|
llvm llvm.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCompiler(pkgName string, config *compileopts.Config) (*Compiler, error) {
|
// NewTargetMachine returns a new llvm.TargetMachine based on the passed-in
|
||||||
c := &Compiler{
|
// configuration. It is used by the compiler and is needed for machine code
|
||||||
compilerContext: compilerContext{
|
// emission.
|
||||||
Config: config,
|
func NewTargetMachine(config *compileopts.Config) (llvm.TargetMachine, error) {
|
||||||
difiles: make(map[string]llvm.Metadata),
|
|
||||||
ditypes: make(map[types.Type]llvm.Metadata),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
target, err := llvm.GetTargetFromTriple(config.Triple())
|
target, err := llvm.GetTargetFromTriple(config.Triple())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return llvm.TargetMachine{}, err
|
||||||
}
|
}
|
||||||
features := strings.Join(config.Features(), ",")
|
features := strings.Join(config.Features(), ",")
|
||||||
c.machine = target.CreateTargetMachine(config.Triple(), config.CPU(), features, llvm.CodeGenLevelDefault, llvm.RelocStatic, llvm.CodeModelDefault)
|
machine := target.CreateTargetMachine(config.Triple(), config.CPU(), features, llvm.CodeGenLevelDefault, llvm.RelocStatic, llvm.CodeModelDefault)
|
||||||
c.targetData = c.machine.CreateTargetData()
|
return machine, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile the given package path or .go file path. Return an error when this
|
||||||
|
// fails (in any stage). If successful it returns the LLVM module and a list of
|
||||||
|
// extra C files to be compiled. If not, one or more errors will be returned.
|
||||||
|
//
|
||||||
|
// The fact that it returns a list of filenames to compile is a layering
|
||||||
|
// violation. Eventually, this Compile function should only compile a single
|
||||||
|
// package and not the whole program, and loading of the program (including CGo
|
||||||
|
// processing) should be moved outside the compiler package.
|
||||||
|
func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Config) (llvm.Module, []string, []error) {
|
||||||
|
c := &compilerContext{
|
||||||
|
Config: config,
|
||||||
|
difiles: make(map[string]llvm.Metadata),
|
||||||
|
ditypes: make(map[types.Type]llvm.Metadata),
|
||||||
|
machine: machine,
|
||||||
|
targetData: machine.CreateTargetData(),
|
||||||
|
}
|
||||||
|
|
||||||
c.ctx = llvm.NewContext()
|
c.ctx = llvm.NewContext()
|
||||||
c.mod = c.ctx.NewModule(pkgName)
|
c.mod = c.ctx.NewModule(pkgName)
|
||||||
c.mod.SetTarget(config.Triple())
|
c.mod.SetTarget(config.Triple())
|
||||||
c.mod.SetDataLayout(c.targetData.String())
|
c.mod.SetDataLayout(c.targetData.String())
|
||||||
c.builder = c.ctx.NewBuilder()
|
|
||||||
if c.Debug() {
|
if c.Debug() {
|
||||||
c.dibuilder = llvm.NewDIBuilder(c.mod)
|
c.dibuilder = llvm.NewDIBuilder(c.mod)
|
||||||
}
|
}
|
||||||
|
@ -131,21 +137,6 @@ func NewCompiler(pkgName string, config *compileopts.Config) (*Compiler, error)
|
||||||
c.funcPtrAddrSpace = dummyFunc.Type().PointerAddressSpace()
|
c.funcPtrAddrSpace = dummyFunc.Type().PointerAddressSpace()
|
||||||
dummyFunc.EraseFromParentAsFunction()
|
dummyFunc.EraseFromParentAsFunction()
|
||||||
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Compiler) Packages() []*loader.Package {
|
|
||||||
return c.ir.LoaderProgram.Sorted()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the LLVM module. Only valid after a successful compile.
|
|
||||||
func (c *Compiler) Module() llvm.Module {
|
|
||||||
return c.mod
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compile the given package path or .go file path. Return an error when this
|
|
||||||
// fails (in any stage).
|
|
||||||
func (c *Compiler) Compile(mainPath string) []error {
|
|
||||||
// Prefix the GOPATH with the system GOROOT, as GOROOT is already set to
|
// Prefix the GOPATH with the system GOROOT, as GOROOT is already set to
|
||||||
// the TinyGo root.
|
// the TinyGo root.
|
||||||
overlayGopath := goenv.Get("GOPATH")
|
overlayGopath := goenv.Get("GOPATH")
|
||||||
|
@ -157,7 +148,7 @@ func (c *Compiler) Compile(mainPath string) []error {
|
||||||
|
|
||||||
wd, err := os.Getwd()
|
wd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []error{err}
|
return c.mod, nil, []error{err}
|
||||||
}
|
}
|
||||||
lprogram := &loader.Program{
|
lprogram := &loader.Program{
|
||||||
Build: &build.Context{
|
Build: &build.Context{
|
||||||
|
@ -217,17 +208,17 @@ func (c *Compiler) Compile(mainPath string) []error {
|
||||||
ClangHeaders: c.ClangHeaders,
|
ClangHeaders: c.ClangHeaders,
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasSuffix(mainPath, ".go") {
|
if strings.HasSuffix(pkgName, ".go") {
|
||||||
_, err = lprogram.ImportFile(mainPath)
|
_, err = lprogram.ImportFile(pkgName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []error{err}
|
return c.mod, nil, []error{err}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_, err = lprogram.Import(mainPath, wd, token.Position{
|
_, err = lprogram.Import(pkgName, wd, token.Position{
|
||||||
Filename: "build command-line-arguments",
|
Filename: "build command-line-arguments",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []error{err}
|
return c.mod, nil, []error{err}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,15 +226,15 @@ func (c *Compiler) Compile(mainPath string) []error {
|
||||||
Filename: "build default import",
|
Filename: "build default import",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []error{err}
|
return c.mod, nil, []error{err}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = lprogram.Parse(c.TestConfig.CompileTestBinary)
|
err = lprogram.Parse(c.TestConfig.CompileTestBinary)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []error{err}
|
return c.mod, nil, []error{err}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ir = ir.NewProgram(lprogram, mainPath)
|
c.ir = ir.NewProgram(lprogram, pkgName)
|
||||||
|
|
||||||
// Run a simple dead code elimination pass.
|
// Run a simple dead code elimination pass.
|
||||||
c.ir.SimpleDCE()
|
c.ir.SimpleDCE()
|
||||||
|
@ -252,7 +243,7 @@ func (c *Compiler) Compile(mainPath string) []error {
|
||||||
if c.Debug() {
|
if c.Debug() {
|
||||||
c.cu = c.dibuilder.CreateCompileUnit(llvm.DICompileUnit{
|
c.cu = c.dibuilder.CreateCompileUnit(llvm.DICompileUnit{
|
||||||
Language: 0xb, // DW_LANG_C99 (0xc, off-by-one?)
|
Language: 0xb, // DW_LANG_C99 (0xc, off-by-one?)
|
||||||
File: mainPath,
|
File: pkgName,
|
||||||
Dir: "",
|
Dir: "",
|
||||||
Producer: "TinyGo",
|
Producer: "TinyGo",
|
||||||
Optimized: true,
|
Optimized: true,
|
||||||
|
@ -281,9 +272,12 @@ func (c *Compiler) Compile(mainPath string) []error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add definitions to declarations.
|
// Add definitions to declarations.
|
||||||
|
var initFuncs []llvm.Value
|
||||||
|
irbuilder := c.ctx.NewBuilder()
|
||||||
|
defer irbuilder.Dispose()
|
||||||
for _, f := range c.ir.Functions {
|
for _, f := range c.ir.Functions {
|
||||||
if f.Synthetic == "package initializer" {
|
if f.Synthetic == "package initializer" {
|
||||||
c.initFuncs = append(c.initFuncs, f.LLVMFn)
|
initFuncs = append(initFuncs, f.LLVMFn)
|
||||||
}
|
}
|
||||||
if f.CName() != "" {
|
if f.CName() != "" {
|
||||||
continue
|
continue
|
||||||
|
@ -294,8 +288,8 @@ func (c *Compiler) Compile(mainPath string) []error {
|
||||||
|
|
||||||
// Create the function definition.
|
// Create the function definition.
|
||||||
b := builder{
|
b := builder{
|
||||||
compilerContext: &c.compilerContext,
|
compilerContext: c,
|
||||||
Builder: c.builder,
|
Builder: irbuilder,
|
||||||
fn: f,
|
fn: f,
|
||||||
locals: make(map[ssa.Value]llvm.Value),
|
locals: make(map[ssa.Value]llvm.Value),
|
||||||
dilocals: make(map[*types.Var]llvm.Metadata),
|
dilocals: make(map[*types.Var]llvm.Metadata),
|
||||||
|
@ -313,14 +307,14 @@ func (c *Compiler) Compile(mainPath string) []error {
|
||||||
if c.Debug() {
|
if c.Debug() {
|
||||||
difunc := c.attachDebugInfo(initFn)
|
difunc := c.attachDebugInfo(initFn)
|
||||||
pos := c.ir.Program.Fset.Position(initFn.Pos())
|
pos := c.ir.Program.Fset.Position(initFn.Pos())
|
||||||
c.builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
|
irbuilder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
|
||||||
}
|
}
|
||||||
block := c.ctx.AddBasicBlock(initFn.LLVMFn, "entry")
|
block := c.ctx.AddBasicBlock(initFn.LLVMFn, "entry")
|
||||||
c.builder.SetInsertPointAtEnd(block)
|
irbuilder.SetInsertPointAtEnd(block)
|
||||||
for _, fn := range c.initFuncs {
|
for _, fn := range initFuncs {
|
||||||
c.builder.CreateCall(fn, []llvm.Value{llvm.Undef(c.i8ptrType), llvm.Undef(c.i8ptrType)}, "")
|
irbuilder.CreateCall(fn, []llvm.Value{llvm.Undef(c.i8ptrType), llvm.Undef(c.i8ptrType)}, "")
|
||||||
}
|
}
|
||||||
c.builder.CreateRetVoid()
|
irbuilder.CreateRetVoid()
|
||||||
|
|
||||||
// Conserve for goroutine lowering. Without marking these as external, they
|
// Conserve for goroutine lowering. Without marking these as external, they
|
||||||
// would be optimized away.
|
// would be optimized away.
|
||||||
|
@ -392,7 +386,15 @@ func (c *Compiler) Compile(mainPath string) []error {
|
||||||
c.dibuilder.Finalize()
|
c.dibuilder.Finalize()
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.diagnostics
|
// Gather the list of (C) file paths that should be included in the build.
|
||||||
|
var extraFiles []string
|
||||||
|
for _, pkg := range c.ir.LoaderProgram.Sorted() {
|
||||||
|
for _, file := range pkg.CFiles {
|
||||||
|
extraFiles = append(extraFiles, filepath.Join(pkg.Package.Dir, file))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.mod, extraFiles, c.diagnostics
|
||||||
}
|
}
|
||||||
|
|
||||||
// getLLVMRuntimeType obtains a named type from the runtime package and returns
|
// getLLVMRuntimeType obtains a named type from the runtime package and returns
|
||||||
|
@ -2577,47 +2579,3 @@ func (b *builder) createUnOp(unop *ssa.UnOp) (llvm.Value, error) {
|
||||||
return llvm.Value{}, b.makeError(unop.Pos(), "todo: unknown unop")
|
return llvm.Value{}, b.makeError(unop.Pos(), "todo: unknown unop")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IR returns the whole IR as a human-readable string.
|
|
||||||
func (c *Compiler) IR() string {
|
|
||||||
return c.mod.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Compiler) Verify() error {
|
|
||||||
return llvm.VerifyModule(c.mod, llvm.PrintMessageAction)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit object file (.o).
|
|
||||||
func (c *Compiler) EmitObject(path string) error {
|
|
||||||
llvmBuf, err := c.machine.EmitToMemoryBuffer(c.mod, llvm.ObjectFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.writeFile(llvmBuf.Bytes(), path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit LLVM bitcode file (.bc).
|
|
||||||
func (c *Compiler) EmitBitcode(path string) error {
|
|
||||||
data := llvm.WriteBitcodeToMemoryBuffer(c.mod).Bytes()
|
|
||||||
return c.writeFile(data, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit LLVM IR source file (.ll).
|
|
||||||
func (c *Compiler) EmitText(path string) error {
|
|
||||||
data := []byte(c.mod.String())
|
|
||||||
return c.writeFile(data, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the data to the file specified by path.
|
|
||||||
func (c *Compiler) writeFile(data []byte, path string) error {
|
|
||||||
// Write output to file
|
|
||||||
f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = f.Write(data)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return f.Close()
|
|
||||||
}
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ type globalInfo struct {
|
||||||
|
|
||||||
// loadASTComments loads comments on globals from the AST, for use later in the
|
// loadASTComments loads comments on globals from the AST, for use later in the
|
||||||
// program. In particular, they are required for //go:extern pragmas on globals.
|
// program. In particular, they are required for //go:extern pragmas on globals.
|
||||||
func (c *Compiler) loadASTComments(lprogram *loader.Program) {
|
func (c *compilerContext) loadASTComments(lprogram *loader.Program) {
|
||||||
c.astComments = map[string]*ast.CommentGroup{}
|
c.astComments = map[string]*ast.CommentGroup{}
|
||||||
for _, pkgInfo := range lprogram.Sorted() {
|
for _, pkgInfo := range lprogram.Sorted() {
|
||||||
for _, file := range pkgInfo.Files {
|
for _, file := range pkgInfo.Files {
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче