Skip to content

Commit 5cc87b4

Browse files
authored
[AsmParser] Add missing globals declarations in incomplete IR mode (llvm#79855)
If `-allow-incomplete-ir` is enabled, automatically insert declarations for missing globals. If a global is only used in calls with the same function type, insert a function declaration with that type. Otherwise, insert a dummy i8 global. The fallback case could be extended with various heuristics (e.g. we could look at load/store types), but I've chosen to keep it simple for now, because I'm unsure to what degree this would really useful without more experience. I expect that in most cases the declaration type doesn't really matter (note that the type of an external global specifies a *minimum* size only, not a precise size). This is a followup to llvm#78421.
1 parent cb6240d commit 5cc87b4

File tree

2 files changed

+52
-12
lines changed

2 files changed

+52
-12
lines changed

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -303,15 +303,7 @@ bool LLParser::validateEndOfModule(bool UpgradeDebugInfo) {
303303
"use of undefined comdat '$" +
304304
ForwardRefComdats.begin()->first + "'");
305305

306-
// Automatically create declarations for intrinsics. Intrinsics can only be
307-
// called directly, so the call function type directly determines the
308-
// declaration function type.
309306
for (const auto &[Name, Info] : make_early_inc_range(ForwardRefVals)) {
310-
if (!StringRef(Name).starts_with("llvm."))
311-
continue;
312-
313-
// Don't do anything if the intrinsic is called with different function
314-
// types. This would result in a verifier error anyway.
315307
auto GetCommonFunctionType = [](Value *V) -> FunctionType * {
316308
FunctionType *FTy = nullptr;
317309
for (User *U : V->users()) {
@@ -322,10 +314,38 @@ bool LLParser::validateEndOfModule(bool UpgradeDebugInfo) {
322314
}
323315
return FTy;
324316
};
325-
if (FunctionType *FTy = GetCommonFunctionType(Info.first)) {
326-
Function *Fn =
327-
Function::Create(FTy, GlobalValue::ExternalLinkage, Name, M);
328-
Info.first->replaceAllUsesWith(Fn);
317+
318+
auto GetDeclarationType = [&](StringRef Name, Value *V) -> Type * {
319+
// Automatically create declarations for intrinsics. Intrinsics can only
320+
// be called directly, so the call function type directly determines the
321+
// declaration function type.
322+
if (Name.starts_with("llvm."))
323+
// Don't do anything if the intrinsic is called with different function
324+
// types. This would result in a verifier error anyway.
325+
return GetCommonFunctionType(V);
326+
327+
if (AllowIncompleteIR) {
328+
// If incomplete IR is allowed, also add declarations for
329+
// non-intrinsics. First check whether this global is only used in
330+
// calls with the same type, in which case we'll insert a function.
331+
if (auto *Ty = GetCommonFunctionType(V))
332+
return Ty;
333+
334+
// Otherwise, fall back to using a dummy i8 type.
335+
return Type::getInt8Ty(Context);
336+
}
337+
return nullptr;
338+
};
339+
340+
if (Type *Ty = GetDeclarationType(Name, Info.first)) {
341+
GlobalValue *GV;
342+
if (auto *FTy = dyn_cast<FunctionType>(Ty))
343+
GV = Function::Create(FTy, GlobalValue::ExternalLinkage, Name, M);
344+
else
345+
GV = new GlobalVariable(*M, Ty, /*isConstant*/ false,
346+
GlobalValue::ExternalLinkage,
347+
/*Initializer*/ nullptr, Name);
348+
Info.first->replaceAllUsesWith(GV);
329349
Info.first->eraseFromParent();
330350
ForwardRefVals.erase(Name);
331351
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
; RUN: opt -S -allow-incomplete-ir < %s | FileCheck %s
2+
3+
; CHECK: @fn2 = external global i8
4+
; CHECK: @g1 = external global i8
5+
; CHECK: @g2 = external global i8
6+
; CHECK: @g3 = external global i8
7+
8+
; CHECK: declare void @fn1(i32)
9+
10+
define ptr @test() {
11+
call void @fn1(i32 0)
12+
call void @fn1(i32 1)
13+
call void @fn2(i32 2)
14+
call void @fn2(i32 2, i32 3)
15+
load i32, ptr @g1
16+
store i32 0, ptr @g1
17+
load i32, ptr @g1
18+
load i64, ptr @g2
19+
ret ptr @g3
20+
}

0 commit comments

Comments
 (0)