mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-27 23:28:42 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2de0635140 | |||
| 9b91cbb841 | |||
| fa6bc6445c |
+92
-29
@@ -169,12 +169,14 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
CodeModel: config.CodeModel(),
|
CodeModel: config.CodeModel(),
|
||||||
RelocationModel: config.RelocationModel(),
|
RelocationModel: config.RelocationModel(),
|
||||||
SizeLevel: sizeLevel,
|
SizeLevel: sizeLevel,
|
||||||
|
TinyGoVersion: goenv.Version,
|
||||||
|
|
||||||
Scheduler: config.Scheduler(),
|
Scheduler: config.Scheduler(),
|
||||||
AutomaticStackSize: config.AutomaticStackSize(),
|
AutomaticStackSize: config.AutomaticStackSize(),
|
||||||
DefaultStackSize: config.StackSize(),
|
DefaultStackSize: config.StackSize(),
|
||||||
NeedsStackObjects: config.NeedsStackObjects(),
|
NeedsStackObjects: config.NeedsStackObjects(),
|
||||||
Debug: true,
|
Debug: true,
|
||||||
|
LTO: config.LTO() != "legacy",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the target machine, which is the LLVM object that contains all
|
// Load the target machine, which is the LLVM object that contains all
|
||||||
@@ -305,7 +307,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
actionID := packageAction{
|
actionID := packageAction{
|
||||||
ImportPath: pkg.ImportPath,
|
ImportPath: pkg.ImportPath,
|
||||||
CompilerBuildID: string(compilerBuildID),
|
CompilerBuildID: string(compilerBuildID),
|
||||||
TinyGoVersion: goenv.Version,
|
|
||||||
LLVMVersion: llvm.Version,
|
LLVMVersion: llvm.Version,
|
||||||
Config: compilerConfig,
|
Config: compilerConfig,
|
||||||
CFlags: pkg.CFlags,
|
CFlags: pkg.CFlags,
|
||||||
@@ -452,18 +453,24 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if runtime.GOOS == "windows" {
|
if compilerConfig.LTO {
|
||||||
// Work around a problem on Windows.
|
buf := llvm.WriteThinLTOBitcodeToMemoryBuffer(mod)
|
||||||
// For some reason, WriteBitcodeToFile causes TinyGo to
|
|
||||||
// exit with the following message:
|
|
||||||
// LLVM ERROR: IO failure on output stream: Bad file descriptor
|
|
||||||
buf := llvm.WriteBitcodeToMemoryBuffer(mod)
|
|
||||||
defer buf.Dispose()
|
defer buf.Dispose()
|
||||||
_, err = f.Write(buf.Bytes())
|
_, err = f.Write(buf.Bytes())
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, write bitcode directly to the file (probably
|
if runtime.GOOS == "windows" {
|
||||||
// faster).
|
// Work around a problem on Windows.
|
||||||
err = llvm.WriteBitcodeToFile(mod, f)
|
// For some reason, WriteBitcodeToFile causes TinyGo to
|
||||||
|
// exit with the following message:
|
||||||
|
// LLVM ERROR: IO failure on output stream: Bad file descriptor
|
||||||
|
buf := llvm.WriteBitcodeToMemoryBuffer(mod)
|
||||||
|
defer buf.Dispose()
|
||||||
|
_, err = f.Write(buf.Bytes())
|
||||||
|
} else {
|
||||||
|
// Otherwise, write bitcode directly to the file (probably
|
||||||
|
// faster).
|
||||||
|
err = llvm.WriteBitcodeToFile(mod, f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// WriteBitcodeToFile doesn't produce a useful error on its
|
// WriteBitcodeToFile doesn't produce a useful error on its
|
||||||
@@ -511,24 +518,11 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
|
|
||||||
// Create runtime.initAll function that calls the runtime
|
// Create runtime.initAll function that calls the runtime
|
||||||
// initializer of each package.
|
// initializer of each package.
|
||||||
llvmInitFn := mod.NamedFunction("runtime.initAll")
|
initAllModule := createInitAll(ctx, config, compilerConfig, lprogram.Sorted())
|
||||||
llvmInitFn.SetLinkage(llvm.InternalLinkage)
|
err := llvm.LinkModules(mod, initAllModule)
|
||||||
llvmInitFn.SetUnnamedAddr(true)
|
if err != nil {
|
||||||
transform.AddStandardAttributes(llvmInitFn, config)
|
return fmt.Errorf("failed to link module: %w", err)
|
||||||
llvmInitFn.Param(0).SetName("context")
|
|
||||||
block := mod.Context().AddBasicBlock(llvmInitFn, "entry")
|
|
||||||
irbuilder := mod.Context().NewBuilder()
|
|
||||||
defer irbuilder.Dispose()
|
|
||||||
irbuilder.SetInsertPointAtEnd(block)
|
|
||||||
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
|
|
||||||
for _, pkg := range lprogram.Sorted() {
|
|
||||||
pkgInit := mod.NamedFunction(pkg.Pkg.Path() + ".init")
|
|
||||||
if pkgInit.IsNil() {
|
|
||||||
panic("init not found for " + pkg.Pkg.Path())
|
|
||||||
}
|
|
||||||
irbuilder.CreateCall(pkgInit.GlobalValueType(), pkgInit, []llvm.Value{llvm.Undef(i8ptrType)}, "")
|
|
||||||
}
|
}
|
||||||
irbuilder.CreateRetVoid()
|
|
||||||
|
|
||||||
// After linking, functions should (as far as possible) be set to
|
// After linking, functions should (as far as possible) be set to
|
||||||
// private linkage or internal linkage. The compiler package marks
|
// private linkage or internal linkage. The compiler package marks
|
||||||
@@ -561,7 +555,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
|
|
||||||
// Run all optimization passes, which are much more effective now
|
// Run all optimization passes, which are much more effective now
|
||||||
// that the optimizer can see the whole program at once.
|
// that the optimizer can see the whole program at once.
|
||||||
err := optimizeProgram(mod, config)
|
err = optimizeProgram(mod, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -622,8 +616,38 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add job to create the runtime.initAll function in a new module.
|
||||||
|
initAllJob := &compileJob{
|
||||||
|
description: "create runtime.initAll",
|
||||||
|
result: filepath.Join(tmpdir, "runtime-initAll.bc"),
|
||||||
|
run: func(job *compileJob) (err error) {
|
||||||
|
// Create module with runtime.initAll.
|
||||||
|
ctx := llvm.NewContext()
|
||||||
|
defer ctx.Dispose()
|
||||||
|
initAllMod := createInitAll(ctx, config, compilerConfig, lprogram.Sorted())
|
||||||
|
defer initAllMod.Dispose()
|
||||||
|
|
||||||
|
// Write module to bitcode file.
|
||||||
|
llvmBuf := llvm.WriteThinLTOBitcodeToMemoryBuffer(initAllMod)
|
||||||
|
defer llvmBuf.Dispose()
|
||||||
|
return os.WriteFile(job.result, llvmBuf.Bytes(), 0666)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare link command.
|
// Prepare link command.
|
||||||
linkerDependencies := []*compileJob{outputObjectFileJob}
|
var linkerDependencies []*compileJob
|
||||||
|
switch config.LTO() {
|
||||||
|
case "legacy":
|
||||||
|
// Link all Go bitcode files together into a single large module and
|
||||||
|
// then do a ThinLTO link with the resulting large module + extra C
|
||||||
|
// files (from CGo etc).
|
||||||
|
linkerDependencies = append(linkerDependencies, outputObjectFileJob)
|
||||||
|
case "thin":
|
||||||
|
// Do a real thin link, with each Go package in a separate translation
|
||||||
|
// unit. This is faster than merging them into one big LTO module.
|
||||||
|
linkerDependencies = append(linkerDependencies, packageJobs...)
|
||||||
|
linkerDependencies = append(linkerDependencies, initAllJob)
|
||||||
|
}
|
||||||
result.Executable = filepath.Join(tmpdir, "main")
|
result.Executable = filepath.Join(tmpdir, "main")
|
||||||
if config.GOOS() == "windows" {
|
if config.GOOS() == "windows" {
|
||||||
result.Executable += ".exe"
|
result.Executable += ".exe"
|
||||||
@@ -1032,6 +1056,45 @@ func createEmbedObjectFile(data, hexSum, sourceFile, sourceDir, tmpdir string, c
|
|||||||
return outfile.Name(), outfile.Close()
|
return outfile.Name(), outfile.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a module with the runtime.initAll function that calls all package
|
||||||
|
// initializers in initialization order.
|
||||||
|
func createInitAll(ctx llvm.Context, config *compileopts.Config, compilerConfig *compiler.Config, pkgs []*loader.Package) llvm.Module {
|
||||||
|
// Create LLVM module.
|
||||||
|
mod := ctx.NewModule("runtime-initAll")
|
||||||
|
|
||||||
|
// Add datalayout string.
|
||||||
|
machine, err := compiler.NewTargetMachine(compilerConfig)
|
||||||
|
if err != nil {
|
||||||
|
panic(err) // extremely unlikely to fail here (NewTargetMachine is called many times before)
|
||||||
|
}
|
||||||
|
defer machine.Dispose()
|
||||||
|
targetData := machine.CreateTargetData()
|
||||||
|
defer targetData.Dispose()
|
||||||
|
mod.SetTarget(config.Triple())
|
||||||
|
mod.SetDataLayout(targetData.String())
|
||||||
|
|
||||||
|
// Create empty runtime.initAll function.
|
||||||
|
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
|
||||||
|
fnType := llvm.FunctionType(ctx.VoidType(), []llvm.Type{i8ptrType}, false)
|
||||||
|
fn := llvm.AddFunction(mod, "runtime.initAll", fnType)
|
||||||
|
fn.SetUnnamedAddr(true)
|
||||||
|
transform.AddStandardAttributes(fn, config)
|
||||||
|
|
||||||
|
// Add calls to package initializers.
|
||||||
|
fn.Param(0).SetName("context")
|
||||||
|
block := mod.Context().AddBasicBlock(fn, "entry")
|
||||||
|
irbuilder := mod.Context().NewBuilder()
|
||||||
|
defer irbuilder.Dispose()
|
||||||
|
irbuilder.SetInsertPointAtEnd(block)
|
||||||
|
for _, pkg := range pkgs {
|
||||||
|
pkgInit := llvm.AddFunction(mod, pkg.Pkg.Path()+".init", fnType)
|
||||||
|
irbuilder.CreateCall(fnType, pkgInit, []llvm.Value{llvm.Undef(i8ptrType)}, "")
|
||||||
|
}
|
||||||
|
irbuilder.CreateRetVoid()
|
||||||
|
|
||||||
|
return mod
|
||||||
|
}
|
||||||
|
|
||||||
// optimizeProgram runs a series of optimizations and transformations that are
|
// optimizeProgram runs a series of optimizations and transformations that are
|
||||||
// needed to convert a program to its final form. Some transformations are not
|
// needed to convert a program to its final form. Some transformations are not
|
||||||
// optional and must be run as the compiler expects them to run.
|
// optional and must be run as the compiler expects them to run.
|
||||||
|
|||||||
@@ -165,6 +165,14 @@ func (c *Config) OptLevels() (optLevel, sizeLevel int, inlinerThreshold uint) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LTO returns one of the possible LTO configurations: legacy or thin.
|
||||||
|
func (c *Config) LTO() string {
|
||||||
|
if c.Options.LTO != "" {
|
||||||
|
return c.Options.LTO
|
||||||
|
}
|
||||||
|
return "legacy"
|
||||||
|
}
|
||||||
|
|
||||||
// PanicStrategy returns the panic strategy selected for this target. Valid
|
// PanicStrategy returns the panic strategy selected for this target. Valid
|
||||||
// values are "print" (print the panic value, then exit) or "trap" (issue a trap
|
// values are "print" (print the panic value, then exit) or "trap" (issue a trap
|
||||||
// instruction).
|
// instruction).
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ var (
|
|||||||
validPrintSizeOptions = []string{"none", "short", "full"}
|
validPrintSizeOptions = []string{"none", "short", "full"}
|
||||||
validPanicStrategyOptions = []string{"print", "trap"}
|
validPanicStrategyOptions = []string{"print", "trap"}
|
||||||
validOptOptions = []string{"none", "0", "1", "2", "s", "z"}
|
validOptOptions = []string{"none", "0", "1", "2", "s", "z"}
|
||||||
|
validLTOOptions = []string{"legacy", "thin"}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options contains extra options to give to the compiler. These options are
|
// Options contains extra options to give to the compiler. These options are
|
||||||
@@ -25,6 +26,7 @@ type Options struct {
|
|||||||
GOARM string // environment variable (only used with GOARCH=arm)
|
GOARM string // environment variable (only used with GOARCH=arm)
|
||||||
Target string
|
Target string
|
||||||
Opt string
|
Opt string
|
||||||
|
LTO string
|
||||||
GC string
|
GC string
|
||||||
PanicStrategy string
|
PanicStrategy string
|
||||||
Scheduler string
|
Scheduler string
|
||||||
@@ -107,6 +109,12 @@ func (o *Options) Verify() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.LTO != "" {
|
||||||
|
if !isInArray(validLTOOptions, o.LTO) {
|
||||||
|
return fmt.Errorf("invalid -lto=%s: valid values are %s", o.LTO, strings.Join(validLTOOptions, ", "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -34,7 +34,9 @@ var stdlibAliases = map[string]string{
|
|||||||
// createAlias implements the function (in the builder) as a call to the alias
|
// createAlias implements the function (in the builder) as a call to the alias
|
||||||
// function.
|
// function.
|
||||||
func (b *builder) createAlias(alias llvm.Value) {
|
func (b *builder) createAlias(alias llvm.Value) {
|
||||||
b.llvmFn.SetVisibility(llvm.HiddenVisibility)
|
if !b.LTO {
|
||||||
|
b.llvmFn.SetVisibility(llvm.HiddenVisibility)
|
||||||
|
}
|
||||||
b.llvmFn.SetUnnamedAddr(true)
|
b.llvmFn.SetUnnamedAddr(true)
|
||||||
|
|
||||||
if b.Debug {
|
if b.Debug {
|
||||||
|
|||||||
+24
-5
@@ -47,6 +47,7 @@ type Config struct {
|
|||||||
CodeModel string
|
CodeModel string
|
||||||
RelocationModel string
|
RelocationModel string
|
||||||
SizeLevel int
|
SizeLevel int
|
||||||
|
TinyGoVersion string // for llvm.ident
|
||||||
|
|
||||||
// Various compiler options that determine how code is generated.
|
// Various compiler options that determine how code is generated.
|
||||||
Scheduler string
|
Scheduler string
|
||||||
@@ -54,6 +55,7 @@ type Config struct {
|
|||||||
DefaultStackSize uint64
|
DefaultStackSize uint64
|
||||||
NeedsStackObjects bool
|
NeedsStackObjects bool
|
||||||
Debug bool // Whether to emit debug information in the LLVM module.
|
Debug bool // Whether to emit debug information in the LLVM module.
|
||||||
|
LTO bool // non-legacy LTO (meaning: package bitcode is merged by the linker)
|
||||||
}
|
}
|
||||||
|
|
||||||
// compilerContext contains function-independent data that should still be
|
// compilerContext contains function-independent data that should still be
|
||||||
@@ -321,6 +323,14 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
|
|||||||
llvm.ConstInt(c.ctx.Int32Type(), 4, false).ConstantAsMetadata(),
|
llvm.ConstInt(c.ctx.Int32Type(), 4, false).ConstantAsMetadata(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
if c.TinyGoVersion != "" {
|
||||||
|
// It is necessary to set llvm.ident, otherwise debugging on MacOS
|
||||||
|
// won't work.
|
||||||
|
c.mod.AddNamedMetadataOperand("llvm.ident",
|
||||||
|
c.ctx.MDNode(([]llvm.Metadata{
|
||||||
|
c.ctx.MDString("TinyGo version " + c.TinyGoVersion),
|
||||||
|
})))
|
||||||
|
}
|
||||||
c.dibuilder.Finalize()
|
c.dibuilder.Finalize()
|
||||||
c.dibuilder.Destroy()
|
c.dibuilder.Destroy()
|
||||||
}
|
}
|
||||||
@@ -888,7 +898,9 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
|
|||||||
c.createEmbedGlobal(member, global, files)
|
c.createEmbedGlobal(member, global, files)
|
||||||
} else if !info.extern {
|
} else if !info.extern {
|
||||||
global.SetInitializer(llvm.ConstNull(global.GlobalValueType()))
|
global.SetInitializer(llvm.ConstNull(global.GlobalValueType()))
|
||||||
global.SetVisibility(llvm.HiddenVisibility)
|
if !c.LTO {
|
||||||
|
global.SetVisibility(llvm.HiddenVisibility)
|
||||||
|
}
|
||||||
if info.section != "" {
|
if info.section != "" {
|
||||||
global.SetSection(info.section)
|
global.SetSection(info.section)
|
||||||
}
|
}
|
||||||
@@ -935,7 +947,9 @@ func (c *compilerContext) createEmbedGlobal(member *ssa.Global, global llvm.Valu
|
|||||||
}
|
}
|
||||||
strObj := c.getEmbedFileString(files[0])
|
strObj := c.getEmbedFileString(files[0])
|
||||||
global.SetInitializer(strObj)
|
global.SetInitializer(strObj)
|
||||||
global.SetVisibility(llvm.HiddenVisibility)
|
if !c.LTO {
|
||||||
|
global.SetVisibility(llvm.HiddenVisibility)
|
||||||
|
}
|
||||||
|
|
||||||
case *types.Slice:
|
case *types.Slice:
|
||||||
if typ.Elem().Underlying().(*types.Basic).Kind() != types.Byte {
|
if typ.Elem().Underlying().(*types.Basic).Kind() != types.Byte {
|
||||||
@@ -959,7 +973,9 @@ func (c *compilerContext) createEmbedGlobal(member *ssa.Global, global llvm.Valu
|
|||||||
sliceLen := llvm.ConstInt(c.uintptrType, file.Size, false)
|
sliceLen := llvm.ConstInt(c.uintptrType, file.Size, false)
|
||||||
sliceObj := c.ctx.ConstStruct([]llvm.Value{slicePtr, sliceLen, sliceLen}, false)
|
sliceObj := c.ctx.ConstStruct([]llvm.Value{slicePtr, sliceLen, sliceLen}, false)
|
||||||
global.SetInitializer(sliceObj)
|
global.SetInitializer(sliceObj)
|
||||||
global.SetVisibility(llvm.HiddenVisibility)
|
if !c.LTO {
|
||||||
|
global.SetVisibility(llvm.HiddenVisibility)
|
||||||
|
}
|
||||||
|
|
||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
// Assume this is an embed.FS struct:
|
// Assume this is an embed.FS struct:
|
||||||
@@ -1042,7 +1058,9 @@ func (c *compilerContext) createEmbedGlobal(member *ssa.Global, global llvm.Valu
|
|||||||
globalInitializer := llvm.ConstNull(c.getLLVMType(member.Type().(*types.Pointer).Elem()))
|
globalInitializer := llvm.ConstNull(c.getLLVMType(member.Type().(*types.Pointer).Elem()))
|
||||||
globalInitializer = c.builder.CreateInsertValue(globalInitializer, sliceGlobal, 0, "")
|
globalInitializer = c.builder.CreateInsertValue(globalInitializer, sliceGlobal, 0, "")
|
||||||
global.SetInitializer(globalInitializer)
|
global.SetInitializer(globalInitializer)
|
||||||
global.SetVisibility(llvm.HiddenVisibility)
|
if !c.LTO {
|
||||||
|
global.SetVisibility(llvm.HiddenVisibility)
|
||||||
|
}
|
||||||
global.SetAlignment(c.targetData.ABITypeAlignment(globalInitializer.Type()))
|
global.SetAlignment(c.targetData.ABITypeAlignment(globalInitializer.Type()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1089,7 +1107,8 @@ func (b *builder) createFunctionStart(intrinsic bool) {
|
|||||||
// assertion error in llvm-project/llvm/include/llvm/IR/GlobalValue.h:236
|
// assertion error in llvm-project/llvm/include/llvm/IR/GlobalValue.h:236
|
||||||
// is thrown.
|
// is thrown.
|
||||||
if b.llvmFn.Linkage() != llvm.InternalLinkage &&
|
if b.llvmFn.Linkage() != llvm.InternalLinkage &&
|
||||||
b.llvmFn.Linkage() != llvm.PrivateLinkage {
|
b.llvmFn.Linkage() != llvm.PrivateLinkage &&
|
||||||
|
!b.LTO {
|
||||||
b.llvmFn.SetVisibility(llvm.HiddenVisibility)
|
b.llvmFn.SetVisibility(llvm.HiddenVisibility)
|
||||||
}
|
}
|
||||||
b.llvmFn.SetUnnamedAddr(true)
|
b.llvmFn.SetUnnamedAddr(true)
|
||||||
|
|||||||
+15
-10
@@ -490,17 +490,22 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
|
|||||||
commaOk = b.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{actualTypeNum}, "")
|
commaOk = b.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{actualTypeNum}, "")
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
globalName := "reflect/types.typeid:" + getTypeCodeName(expr.AssertedType)
|
if b.LTO {
|
||||||
assertedTypeCodeGlobal := b.mod.NamedGlobal(globalName)
|
assertedTypeCodeGlobal := b.getTypeCode(expr.AssertedType)
|
||||||
if assertedTypeCodeGlobal.IsNil() {
|
commaOk = b.CreateICmp(llvm.IntEQ, actualTypeNum, assertedTypeCodeGlobal, "commaok")
|
||||||
// Create a new typecode global.
|
} else {
|
||||||
assertedTypeCodeGlobal = llvm.AddGlobal(b.mod, b.ctx.Int8Type(), globalName)
|
globalName := "reflect/types.typeid:" + getTypeCodeName(expr.AssertedType)
|
||||||
assertedTypeCodeGlobal.SetGlobalConstant(true)
|
assertedTypeCodeGlobal := b.mod.NamedGlobal(globalName)
|
||||||
|
if assertedTypeCodeGlobal.IsNil() {
|
||||||
|
// Create a new typecode global.
|
||||||
|
assertedTypeCodeGlobal = llvm.AddGlobal(b.mod, b.ctx.Int8Type(), globalName)
|
||||||
|
assertedTypeCodeGlobal.SetGlobalConstant(true)
|
||||||
|
}
|
||||||
|
// Type assert on concrete type.
|
||||||
|
// Call runtime.typeAssert, which will be lowered to a simple icmp
|
||||||
|
// or const false in the interface lowering pass.
|
||||||
|
commaOk = b.createRuntimeCall("typeAssert", []llvm.Value{actualTypeNum, assertedTypeCodeGlobal}, "typecode")
|
||||||
}
|
}
|
||||||
// Type assert on concrete type.
|
|
||||||
// Call runtime.typeAssert, which will be lowered to a simple icmp or
|
|
||||||
// const false in the interface lowering pass.
|
|
||||||
commaOk = b.createRuntimeCall("typeAssert", []llvm.Value{actualTypeNum, assertedTypeCodeGlobal}, "typecode")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add 2 new basic blocks (that should get optimized away): one for the
|
// Add 2 new basic blocks (that should get optimized away): one for the
|
||||||
|
|||||||
@@ -45,7 +45,9 @@ func (b *builder) createInterruptGlobal(instr *ssa.CallCommon) (llvm.Value, erro
|
|||||||
globalLLVMType := b.getLLVMType(globalType)
|
globalLLVMType := b.getLLVMType(globalType)
|
||||||
globalName := b.fn.Package().Pkg.Path() + "$interrupt" + strconv.FormatInt(id.Int64(), 10)
|
globalName := b.fn.Package().Pkg.Path() + "$interrupt" + strconv.FormatInt(id.Int64(), 10)
|
||||||
global := llvm.AddGlobal(b.mod, globalLLVMType, globalName)
|
global := llvm.AddGlobal(b.mod, globalLLVMType, globalName)
|
||||||
global.SetVisibility(llvm.HiddenVisibility)
|
if !b.LTO {
|
||||||
|
global.SetVisibility(llvm.HiddenVisibility)
|
||||||
|
}
|
||||||
global.SetGlobalConstant(true)
|
global.SetGlobalConstant(true)
|
||||||
global.SetUnnamedAddr(true)
|
global.SetUnnamedAddr(true)
|
||||||
initializer := llvm.ConstNull(globalLLVMType)
|
initializer := llvm.ConstNull(globalLLVMType)
|
||||||
|
|||||||
@@ -1357,6 +1357,7 @@ func main() {
|
|||||||
command := os.Args[1]
|
command := os.Args[1]
|
||||||
|
|
||||||
opt := flag.String("opt", "z", "optimization level: 0, 1, 2, s, z")
|
opt := flag.String("opt", "z", "optimization level: 0, 1, 2, s, z")
|
||||||
|
lto := flag.String("lto", "legacy", "LTO mode: legacy or thin")
|
||||||
gc := flag.String("gc", "", "garbage collector to use (none, leaking, conservative)")
|
gc := flag.String("gc", "", "garbage collector to use (none, leaking, conservative)")
|
||||||
panicStrategy := flag.String("panic", "print", "panic strategy (print, trap)")
|
panicStrategy := flag.String("panic", "print", "panic strategy (print, trap)")
|
||||||
scheduler := flag.String("scheduler", "", "which scheduler to use (none, tasks, asyncify)")
|
scheduler := flag.String("scheduler", "", "which scheduler to use (none, tasks, asyncify)")
|
||||||
@@ -1459,6 +1460,7 @@ func main() {
|
|||||||
Target: *target,
|
Target: *target,
|
||||||
StackSize: stackSize,
|
StackSize: stackSize,
|
||||||
Opt: *opt,
|
Opt: *opt,
|
||||||
|
LTO: *lto,
|
||||||
GC: *gc,
|
GC: *gc,
|
||||||
PanicStrategy: *panicStrategy,
|
PanicStrategy: *panicStrategy,
|
||||||
Scheduler: *scheduler,
|
Scheduler: *scheduler,
|
||||||
|
|||||||
@@ -105,6 +105,13 @@ func TestBuild(t *testing.T) {
|
|||||||
runTestWithConfig("print.go", t, opts, nil, nil)
|
runTestWithConfig("print.go", t, opts, nil, nil)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("lto=thin", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
opts := optionsFromTarget("", sema)
|
||||||
|
opts.LTO = "thin"
|
||||||
|
runTestWithConfig("init.go", t, opts, nil, nil)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("ldflags", func(t *testing.T) {
|
t.Run("ldflags", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
opts := optionsFromTarget("", sema)
|
opts := optionsFromTarget("", sema)
|
||||||
|
|||||||
Reference in New Issue
Block a user