@@ -18,10 +18,82 @@ import (
18
18
"github.com/go-llvm/llvm"
19
19
)
20
20
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
+
21
92
type unit struct {
22
93
* 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
25
97
26
98
// funcDescriptors maps *ssa.Functions to function descriptors,
27
99
// the first-class representation of functions.
@@ -39,6 +111,7 @@ func newUnit(c *compiler, pkg *ssa.Package) *unit {
39
111
compiler : c ,
40
112
pkg : pkg ,
41
113
globals : make (map [ssa.Value ]llvm.Value ),
114
+ globalInits : make (map [llvm.Value ]* globalInit ),
42
115
funcDescriptors : make (map [* ssa.Function ]llvm.Value ),
43
116
undefinedFuncs : make (map [* ssa.Function ]bool ),
44
117
}
@@ -100,13 +173,12 @@ func (u *unit) translatePackage(pkg *ssa.Package) {
100
173
llelemtyp := u .llvmtypes .ToLLVM (elemtyp )
101
174
vname := u .types .mc .mangleGlobalName (v )
102
175
global := llvm .AddGlobal (u .module .Module , llelemtyp , vname )
103
- global .SetInitializer (llvm .ConstNull (llelemtyp ))
104
176
if ! v .Object ().Exported () {
105
177
global .SetLinkage (llvm .InternalLinkage )
106
178
}
179
+ u .addGlobal (global , elemtyp )
107
180
global = llvm .ConstBitCast (global , u .llvmtypes .ToLLVM (v .Type ()))
108
181
u .globals [v ] = global
109
- u .maybeAddGcRoot (global , elemtyp )
110
182
case * ssa.Type :
111
183
u .types .getTypeDescriptorPointer (v .Type ())
112
184
}
@@ -122,9 +194,17 @@ func (u *unit) translatePackage(pkg *ssa.Package) {
122
194
// Define remaining functions that were resolved during
123
195
// runtime type mapping, but not defined.
124
196
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
+ }
125
203
}
126
204
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
+
128
208
if hasPointers (ty ) {
129
209
global = llvm .ConstBitCast (global , llvm .PointerType (llvm .Int8Type (), 0 ))
130
210
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 {
672
752
// TODO(pcc): Explicitly check that this is a constant GEP.
673
753
// I don't think there are any other kinds of constantexpr which
674
754
// 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 () &&
676
756
addr .Operand (1 ).IsNull () {
677
757
gv := addr .Operand (0 )
758
+ globalInit , ok := fr .globalInits [gv ]
759
+ if ! ok {
760
+ return false
761
+ }
678
762
indices := make ([]uint32 , addr .OperandsCount ()- 2 )
679
763
for i := range indices {
680
764
op := addr .Operand (i + 2 )
@@ -683,11 +767,14 @@ func (fr *frame) maybeStoreInInitializer(val, addr llvm.Value) bool {
683
767
}
684
768
indices [i ] = uint32 (op .ZExtValue ())
685
769
}
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 )
690
771
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
691
778
} else {
692
779
return false
693
780
}
@@ -714,8 +801,7 @@ func (fr *frame) instruction(instr ssa.Instruction) {
714
801
// variables as static initializations.
715
802
global := llvm .AddGlobal (fr .module .Module , llvmtyp , "" )
716
803
global .SetLinkage (llvm .InternalLinkage )
717
- global .SetInitializer (llvm .ConstNull (llvmtyp ))
718
- fr .maybeAddGcRoot (global , typ )
804
+ fr .addGlobal (global , typ )
719
805
ptr := llvm .ConstBitCast (global , llvm .PointerType (llvm .Int8Type (), 0 ))
720
806
fr .env [instr ] = newValue (ptr , instr .Type ())
721
807
} else {
0 commit comments