summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llgo/cmd/gllgo/gllgo.go1
-rw-r--r--llgo/irgen/compiler.go23
-rw-r--r--llgo/irgen/ssa.go59
-rw-r--r--llgo/test/irgen/imports.go20
4 files changed, 92 insertions, 11 deletions
diff --git a/llgo/cmd/gllgo/gllgo.go b/llgo/cmd/gllgo/gllgo.go
index e58686e57dc..5aee3211b24 100644
--- a/llgo/cmd/gllgo/gllgo.go
+++ b/llgo/cmd/gllgo/gllgo.go
@@ -71,6 +71,7 @@ func initCompiler(opts *driverOptions) (*irgen.Compiler, error) {
DebugPrefixMaps: opts.debugPrefixMaps,
DumpSSA: opts.dumpSSA,
GccgoPath: opts.gccgoPath,
+ GccgoABI: opts.gccgoPath != "",
ImportPaths: importPaths,
SanitizerAttribute: opts.sanitizer.getAttribute(),
}
diff --git a/llgo/irgen/compiler.go b/llgo/irgen/compiler.go
index 60bd62f7196..16c3988ba7b 100644
--- a/llgo/irgen/compiler.go
+++ b/llgo/irgen/compiler.go
@@ -75,6 +75,9 @@ type CompilerOptions struct {
// path in ImportPaths.
GccgoPath string
+ // Whether to use the gccgo ABI.
+ GccgoABI bool
+
// ImportPaths is the list of additional import paths
ImportPaths []string
@@ -322,8 +325,6 @@ func (c *compiler) buildPackageInitData(mainPkg *ssa.Package) gccgoimporter.Init
}
func (c *compiler) createInitMainFunction(mainPkg *ssa.Package) {
- initdata := c.buildPackageInitData(mainPkg)
-
ftyp := llvm.FunctionType(llvm.VoidType(), nil, false)
initMain := llvm.AddFunction(c.module.Module, "__go_init_main", ftyp)
c.addCommonFunctionAttrs(initMain)
@@ -333,6 +334,17 @@ func (c *compiler) createInitMainFunction(mainPkg *ssa.Package) {
defer builder.Dispose()
builder.SetInsertPointAtEnd(entry)
+ if !c.GccgoABI {
+ initfn := c.module.Module.NamedFunction("main..import")
+ if !initfn.IsNil() {
+ builder.CreateCall(initfn, nil, "")
+ }
+ builder.CreateRetVoid()
+ return
+ }
+
+ initdata := c.buildPackageInitData(mainPkg)
+
for _, init := range initdata.Inits {
initfn := c.module.Module.NamedFunction(init.InitFunc)
if initfn.IsNil() {
@@ -348,8 +360,13 @@ func (c *compiler) buildExportData(mainPkg *ssa.Package) []byte {
exportData := importer.ExportData(mainPkg.Object)
b := bytes.NewBuffer(exportData)
+ b.WriteString("v1;\n")
+ if !c.GccgoABI {
+ return b.Bytes()
+ }
+
initdata := c.buildPackageInitData(mainPkg)
- b.WriteString("v1;\npriority ")
+ b.WriteString("priority ")
b.WriteString(strconv.Itoa(initdata.Priority))
b.WriteString(";\n")
diff --git a/llgo/irgen/ssa.go b/llgo/irgen/ssa.go
index 706eb7790e7..1b09b71a7d9 100644
--- a/llgo/irgen/ssa.go
+++ b/llgo/irgen/ssa.go
@@ -409,11 +409,6 @@ func (u *unit) defineFunction(f *ssa.Function) {
}
}
- // If this is the "init" function, enable init-specific optimizations.
- if !isMethod && f.Name() == "init" {
- fr.isInit = true
- }
-
// If the function contains any defers, we must first create
// an unwind block. We can short-circuit the check for defers with
// f.Recover != nil.
@@ -422,8 +417,20 @@ func (u *unit) defineFunction(f *ssa.Function) {
fr.frameptr = fr.builder.CreateAlloca(llvm.Int8Type(), "")
}
- term := fr.builder.CreateBr(fr.blocks[0])
- fr.allocaBuilder.SetInsertPointBefore(term)
+ // Keep track of the block into which we need to insert the call
+ // to __go_register_gc_roots. This needs to be inserted after the
+ // init guard check under the llgo ABI.
+ var registerGcBlock llvm.BasicBlock
+
+ // If this is the "init" function, emit the init guard check and
+ // enable init-specific optimizations.
+ if !isMethod && f.Name() == "init" {
+ registerGcBlock = fr.emitInitPrologue()
+ fr.isInit = true
+ }
+
+ fr.builder.CreateBr(fr.blocks[0])
+ fr.allocaBuilder.SetInsertPointBefore(prologueBlock.FirstInstruction())
for _, block := range f.DomPreorder() {
fr.translateBlock(block, fr.blocks[block.Index])
@@ -439,7 +446,7 @@ func (u *unit) defineFunction(f *ssa.Function) {
// after generating code for it because allocations may have caused
// additional GC roots to be created.
if fr.isInit {
- fr.builder.SetInsertPointBefore(prologueBlock.FirstInstruction())
+ fr.builder.SetInsertPointBefore(registerGcBlock.FirstInstruction())
fr.registerGcRoots()
}
}
@@ -484,6 +491,42 @@ func (fr *frame) dispose() {
fr.allocaBuilder.Dispose()
}
+// emitInitPrologue emits the init-specific function prologue (guard check and
+// initialization of dependent packages under the llgo native ABI), and returns
+// the basic block into which the GC registration call should be emitted.
+func (fr *frame) emitInitPrologue() llvm.BasicBlock {
+ if fr.GccgoABI {
+ return fr.builder.GetInsertBlock()
+ }
+
+ initGuard := llvm.AddGlobal(fr.module.Module, llvm.Int1Type(), "init$guard")
+ initGuard.SetLinkage(llvm.InternalLinkage)
+ initGuard.SetInitializer(llvm.ConstNull(llvm.Int1Type()))
+
+ returnBlock := llvm.AddBasicBlock(fr.function, "")
+ initBlock := llvm.AddBasicBlock(fr.function, "")
+
+ initGuardVal := fr.builder.CreateLoad(initGuard, "")
+ fr.builder.CreateCondBr(initGuardVal, returnBlock, initBlock)
+
+ fr.builder.SetInsertPointAtEnd(returnBlock)
+ fr.builder.CreateRetVoid()
+
+ fr.builder.SetInsertPointAtEnd(initBlock)
+ fr.builder.CreateStore(llvm.ConstInt(llvm.Int1Type(), 1, false), initGuard)
+ ftyp := llvm.FunctionType(llvm.VoidType(), nil, false)
+ for _, pkg := range fr.pkg.Object.Imports() {
+ initname := ManglePackagePath(pkg.Path()) + "..import"
+ initfn := fr.module.Module.NamedFunction(initname)
+ if initfn.IsNil() {
+ initfn = llvm.AddFunction(fr.module.Module, initname, ftyp)
+ }
+ fr.builder.CreateCall(initfn, nil, "")
+ }
+
+ return initBlock
+}
+
// bridgeRecoverFunc creates a function that may call recover(), and creates
// a call to it from the current frame. The created function will be called
// with a boolean parameter that indicates whether it may call recover().
diff --git a/llgo/test/irgen/imports.go b/llgo/test/irgen/imports.go
new file mode 100644
index 00000000000..125bd5ff251
--- /dev/null
+++ b/llgo/test/irgen/imports.go
@@ -0,0 +1,20 @@
+// RUN: llgo -S -emit-llvm -o - %s | FileCheck %s
+
+package foo
+
+import _ "fmt"
+
+var X interface{}
+
+// CHECK: @"init$guard" = internal global i1 false
+
+// CHECK: define void @foo..import()
+// CHECK-NEXT: :
+// CHECK-NEXT: %[[N:.*]] = load i1* @"init$guard"
+// CHECK-NEXT: br i1 %[[N]], label %{{.*}}, label %[[L:.*]]
+
+// CHECK: ; <label>:[[L]]
+// CHECK-NEXT: call void @__go_register_gc_roots
+// CHECK-NEXT: store i1 true, i1* @"init$guard"
+// CHECK-NEXT: call void @fmt..import()
+// CHECK-NEXT: br label
OpenPOWER on IntegriCloud