Skip to content
This repository was archived by the owner on Dec 14, 2023. It is now read-only.

Commit 178c22c

Browse files
committed
Merge pull request #199 from pcc/libgo-init
Build global aggregate initializers with Create{Array,Struct}
2 parents 8183eb4 + 1c29a30 commit 178c22c

File tree

1 file changed

+98
-12
lines changed

1 file changed

+98
-12
lines changed

ssa.go

Lines changed: 98 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,82 @@ import (
1818
"github.com/go-llvm/llvm"
1919
)
2020

21+
// A globalInit is used to temporarily store a global's initializer until
22+
// we are ready to build it.
23+
type globalInit struct {
24+
val llvm.Value
25+
elems []globalInit
26+
}
27+
28+
func (gi *globalInit) update(typ llvm.Type, indices []uint32, val llvm.Value) {
29+
if len(indices) == 0 {
30+
gi.val = val
31+
return
32+
}
33+
34+
if gi.val.C != nil {
35+
gi.val = llvm.ConstInsertValue(gi.val, val, indices)
36+
}
37+
38+
tk := typ.TypeKind()
39+
40+
if len(gi.elems) == 0 {
41+
switch tk {
42+
case llvm.StructTypeKind:
43+
gi.elems = make([]globalInit, typ.StructElementTypesCount())
44+
case llvm.ArrayTypeKind:
45+
gi.elems = make([]globalInit, typ.ArrayLength())
46+
default:
47+
panic("unexpected type")
48+
}
49+
}
50+
51+
var eltyp llvm.Type
52+
switch tk {
53+
case llvm.StructTypeKind:
54+
eltyp = typ.StructElementTypes()[indices[0]]
55+
case llvm.ArrayTypeKind:
56+
eltyp = typ.ElementType()
57+
default:
58+
panic("unexpected type")
59+
}
60+
61+
gi.elems[indices[0]].update(eltyp, indices[1:], val)
62+
}
63+
64+
func (gi *globalInit) build(typ llvm.Type) llvm.Value {
65+
if gi.val.C != nil {
66+
return gi.val
67+
}
68+
if len(gi.elems) == 0 {
69+
return llvm.ConstNull(typ)
70+
}
71+
72+
switch typ.TypeKind() {
73+
case llvm.StructTypeKind:
74+
eltypes := typ.StructElementTypes()
75+
elems := make([]llvm.Value, len(eltypes))
76+
for i, eltyp := range eltypes {
77+
elems[i] = gi.elems[i].build(eltyp)
78+
}
79+
return llvm.ConstStruct(elems, false)
80+
case llvm.ArrayTypeKind:
81+
eltyp := typ.ElementType()
82+
elems := make([]llvm.Value, len(gi.elems))
83+
for i := range gi.elems {
84+
elems[i] = gi.elems[i].build(eltyp)
85+
}
86+
return llvm.ConstArray(eltyp, elems)
87+
default:
88+
panic("unexpected type")
89+
}
90+
}
91+
2192
type unit struct {
2293
*compiler
23-
pkg *ssa.Package
24-
globals map[ssa.Value]llvm.Value
94+
pkg *ssa.Package
95+
globals map[ssa.Value]llvm.Value
96+
globalInits map[llvm.Value]*globalInit
2597

2698
// funcDescriptors maps *ssa.Functions to function descriptors,
2799
// the first-class representation of functions.
@@ -39,6 +111,7 @@ func newUnit(c *compiler, pkg *ssa.Package) *unit {
39111
compiler: c,
40112
pkg: pkg,
41113
globals: make(map[ssa.Value]llvm.Value),
114+
globalInits: make(map[llvm.Value]*globalInit),
42115
funcDescriptors: make(map[*ssa.Function]llvm.Value),
43116
undefinedFuncs: make(map[*ssa.Function]bool),
44117
}
@@ -100,13 +173,12 @@ func (u *unit) translatePackage(pkg *ssa.Package) {
100173
llelemtyp := u.llvmtypes.ToLLVM(elemtyp)
101174
vname := u.types.mc.mangleGlobalName(v)
102175
global := llvm.AddGlobal(u.module.Module, llelemtyp, vname)
103-
global.SetInitializer(llvm.ConstNull(llelemtyp))
104176
if !v.Object().Exported() {
105177
global.SetLinkage(llvm.InternalLinkage)
106178
}
179+
u.addGlobal(global, elemtyp)
107180
global = llvm.ConstBitCast(global, u.llvmtypes.ToLLVM(v.Type()))
108181
u.globals[v] = global
109-
u.maybeAddGcRoot(global, elemtyp)
110182
case *ssa.Type:
111183
u.types.getTypeDescriptorPointer(v.Type())
112184
}
@@ -122,9 +194,17 @@ func (u *unit) translatePackage(pkg *ssa.Package) {
122194
// Define remaining functions that were resolved during
123195
// runtime type mapping, but not defined.
124196
u.defineFunctionsInOrder(u.undefinedFuncs)
197+
198+
// Set initializers for globals.
199+
for global, init := range u.globalInits {
200+
initval := init.build(global.Type().ElementType())
201+
global.SetInitializer(initval)
202+
}
125203
}
126204

127-
func (u *unit) maybeAddGcRoot(global llvm.Value, ty types.Type) {
205+
func (u *unit) addGlobal(global llvm.Value, ty types.Type) {
206+
u.globalInits[global] = new(globalInit)
207+
128208
if hasPointers(ty) {
129209
global = llvm.ConstBitCast(global, llvm.PointerType(llvm.Int8Type(), 0))
130210
size := llvm.ConstInt(u.types.inttype, uint64(u.types.Sizeof(ty)), false)
@@ -672,9 +752,13 @@ func (fr *frame) maybeStoreInInitializer(val, addr llvm.Value) bool {
672752
// TODO(pcc): Explicitly check that this is a constant GEP.
673753
// I don't think there are any other kinds of constantexpr which
674754
// satisfy the conditions we test for here, so this is probably safe.
675-
!addr.Operand(0).IsAGlobalVariable().IsNil() && !addr.Operand(0).Initializer().IsNil() &&
755+
!addr.Operand(0).IsAGlobalVariable().IsNil() &&
676756
addr.Operand(1).IsNull() {
677757
gv := addr.Operand(0)
758+
globalInit, ok := fr.globalInits[gv]
759+
if !ok {
760+
return false
761+
}
678762
indices := make([]uint32, addr.OperandsCount()-2)
679763
for i := range indices {
680764
op := addr.Operand(i + 2)
@@ -683,11 +767,14 @@ func (fr *frame) maybeStoreInInitializer(val, addr llvm.Value) bool {
683767
}
684768
indices[i] = uint32(op.ZExtValue())
685769
}
686-
gv.SetInitializer(llvm.ConstInsertValue(gv.Initializer(), val, indices))
687-
return true
688-
} else if !addr.IsAGlobalVariable().IsNil() && !addr.Initializer().IsNil() {
689-
addr.SetInitializer(val)
770+
globalInit.update(gv.Type().ElementType(), indices, val)
690771
return true
772+
} else if !addr.IsAGlobalVariable().IsNil() {
773+
if globalInit, ok := fr.globalInits[addr]; ok {
774+
globalInit.update(addr.Type().ElementType(), nil, val)
775+
return true
776+
}
777+
return false
691778
} else {
692779
return false
693780
}
@@ -714,8 +801,7 @@ func (fr *frame) instruction(instr ssa.Instruction) {
714801
// variables as static initializations.
715802
global := llvm.AddGlobal(fr.module.Module, llvmtyp, "")
716803
global.SetLinkage(llvm.InternalLinkage)
717-
global.SetInitializer(llvm.ConstNull(llvmtyp))
718-
fr.maybeAddGcRoot(global, typ)
804+
fr.addGlobal(global, typ)
719805
ptr := llvm.ConstBitCast(global, llvm.PointerType(llvm.Int8Type(), 0))
720806
fr.env[instr] = newValue(ptr, instr.Type())
721807
} else {

0 commit comments

Comments
 (0)