Skip to content

Commit f7290c9

Browse files
committed
[NFC] Add a utility to easily emit lazy variable definitions
1 parent 1f7c2fa commit f7290c9

File tree

3 files changed

+89
-13
lines changed

3 files changed

+89
-13
lines changed

lib/IRGen/GenDecl.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3357,6 +3357,20 @@ static llvm::Constant *getElementBitCast(llvm::Constant *ptr,
33573357
}
33583358
}
33593359

3360+
llvm::Constant *
3361+
IRGenModule::getOrCreateLazyGlobalVariable(LinkEntity entity,
3362+
llvm::function_ref<ConstantInitFuture(ConstantInitBuilder &)> build,
3363+
llvm::function_ref<void(llvm::GlobalVariable *)> finish) {
3364+
auto defaultType = entity.getDefaultDeclarationType(*this);
3365+
3366+
LazyConstantInitializer lazyInitializer = {
3367+
defaultType, build, finish
3368+
};
3369+
return getAddrOfLLVMVariable(entity,
3370+
ConstantInit::getLazy(&lazyInitializer),
3371+
DebugTypeInfo(), defaultType);
3372+
}
3373+
33603374
/// Return a reference to an object that's suitable for being used for
33613375
/// the given kind of reference.
33623376
///
@@ -3429,7 +3443,7 @@ IRGenModule::getAddrOfLLVMVariable(LinkEntity entity,
34293443

34303444
// If we're looking to define something, we may need to replace a
34313445
// forward declaration.
3432-
if (definitionType) {
3446+
if (!definition.isLazy() && definitionType) {
34333447
assert(existing->isDeclaration() && "already defined");
34343448
updateLinkageForDefinition(*this, existing, entity);
34353449

@@ -3461,6 +3475,21 @@ IRGenModule::getAddrOfLLVMVariable(LinkEntity entity,
34613475
if (auto existing = Module.getNamedGlobal(link.getName()))
34623476
return getElementBitCast(existing, defaultType);
34633477

3478+
const LazyConstantInitializer *lazyInitializer = nullptr;
3479+
Optional<ConstantInitBuilder> lazyBuilder;
3480+
if (definition.isLazy()) {
3481+
lazyInitializer = definition.getLazy();
3482+
lazyBuilder.emplace(*this);
3483+
3484+
// Build the lazy initializer as a future.
3485+
auto future = lazyInitializer->Build(*lazyBuilder);
3486+
3487+
// Set the future as our definition and set its type as the
3488+
// definition type.
3489+
definitionType = future.getType();
3490+
definition = future;
3491+
}
3492+
34643493
// If we're not defining the object now, forward declare it with the default
34653494
// type.
34663495
if (!definitionType) definitionType = defaultType;
@@ -3474,6 +3503,11 @@ IRGenModule::getAddrOfLLVMVariable(LinkEntity entity,
34743503
definition.getInit().installInGlobal(var);
34753504
}
34763505

3506+
// Call the creation callback.
3507+
if (lazyInitializer) {
3508+
lazyInitializer->Create(var);
3509+
}
3510+
34773511
// If we have an existing entry, destroy it, replacing it with the
34783512
// new variable.
34793513
if (entry) {

lib/IRGen/IRGen.h

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ namespace swift {
3636

3737
namespace irgen {
3838
using Lowering::AbstractionPattern;
39+
class ConstantInitBuilder;
3940
using clang::CodeGen::ConstantInitFuture;
4041
class IRGenFunction;
4142

@@ -166,48 +167,85 @@ enum class SymbolReferenceKind : uint8_t {
166167
Far_Relative_Indirectable,
167168
};
168169

170+
/// A lazy constant initializer.
171+
struct LazyConstantInitializer {
172+
llvm::Type *DefaultType;
173+
llvm::function_ref<ConstantInitFuture(ConstantInitBuilder &)> Build;
174+
llvm::function_ref<void(llvm::GlobalVariable *)> Create;
175+
};
176+
169177
/// An initial value for a definition of an llvm::GlobalVariable.
170178
class ConstantInit {
171-
llvm::PointerUnion<ConstantInitFuture, llvm::Type*> Data;
179+
union {
180+
ConstantInitFuture Future;
181+
const LazyConstantInitializer *Lazy;
182+
llvm::Type *Delayed;
183+
};
184+
enum class Kind {
185+
None, Future, Lazy, Delayed
186+
} TheKind;
187+
172188
public:
173189
/// No initializer is given. When this is used as an argument to
174190
/// a getAddrOf... API, it means that only a declaration is being
175191
/// requested.
176-
ConstantInit() {}
192+
ConstantInit() : TheKind(Kind::None) {}
177193

178194
/// Use a concrete value as a concrete initializer.
179195
ConstantInit(llvm::Constant *initializer)
180-
: Data(ConstantInitFuture(initializer)) {}
196+
: Future(ConstantInitFuture(initializer)), TheKind(Kind::Future) {}
181197

182198
/// Use a ConstantInitBuilder future as a concrete initializer.
183-
/*implicit*/ ConstantInit(ConstantInitFuture future) : Data(future) {
199+
/*implicit*/ ConstantInit(ConstantInitFuture future)
200+
: Future(future), TheKind(Kind::Future) {
184201
assert(future && "don't pass around null futures");
185202
}
186203

204+
static ConstantInit getLazy(const LazyConstantInitializer *initializer) {
205+
assert(initializer && "null lazy initializer");
206+
auto result = ConstantInit();
207+
result.TheKind = Kind::Lazy;
208+
result.Lazy = initializer;
209+
return result;
210+
}
211+
187212
/// There will be a definition (with the given type), but we don't
188213
/// have it yet.
189214
static ConstantInit getDelayed(llvm::Type *type) {
190215
auto result = ConstantInit();
191-
result.Data = type;
216+
result.TheKind = Kind::Delayed;
217+
result.Delayed = type;
192218
return result;
193219
}
194220

195-
explicit operator bool() const { return bool(Data); }
221+
explicit operator bool() const { return TheKind != Kind::None; }
196222

197223
inline llvm::Type *getType() const {
198-
assert(Data && "not a definition");
199-
if (auto type = Data.dyn_cast<llvm::Type*>()) {
200-
return type;
224+
assert(TheKind != Kind::None && "not a definition");
225+
if (TheKind == Kind::Delayed) {
226+
return Delayed;
227+
} else if (TheKind == Kind::Lazy) {
228+
return Lazy->DefaultType;
201229
} else {
202-
return Data.get<ConstantInitFuture>().getType();
230+
assert(TheKind == Kind::Future);
231+
return Future.getType();
203232
}
204233
}
205234

235+
bool isLazy() const {
236+
return TheKind == Kind::Lazy;
237+
}
238+
const LazyConstantInitializer *getLazy() const {
239+
assert(isLazy());
240+
return Lazy;
241+
}
242+
206243
bool hasInit() const {
207-
return Data.is<ConstantInitFuture>();
244+
return TheKind == Kind::Future;
208245
}
209246
ConstantInitFuture getInit() const {
210-
return Data.get<ConstantInitFuture>();
247+
assert(hasInit());
248+
return Future;
211249
}
212250
};
213251

lib/IRGen/IRGenModule.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,10 @@ class IRGenModule {
10621062

10631063
ConstantIntegerLiteral getConstantIntegerLiteral(APInt value);
10641064

1065+
llvm::Constant *getOrCreateLazyGlobalVariable(LinkEntity entity,
1066+
llvm::function_ref<ConstantInitFuture(ConstantInitBuilder &)> build,
1067+
llvm::function_ref<void(llvm::GlobalVariable *)> finish);
1068+
10651069
void addUsedGlobal(llvm::GlobalValue *global);
10661070
void addCompilerUsedGlobal(llvm::GlobalValue *global);
10671071
void addObjCClass(llvm::Constant *addr, bool nonlazy);

0 commit comments

Comments
 (0)