Skip to content

Commit cc19416

Browse files
committed
[AsmParser] Add support for reading incomplete IR
Add an `-allow-incomplete-ir` flag to the IR parser, which allows reading IR with missing declarations. This is intended to produce a best-effort interpretation of the IR, along the same lines of what we would manually do when taking, for example, a function from `-print-after-all` output and fixing it up to be valid IR. This patch only supports dropping references to undeclared metadata, either by dropping metadata attachments from instructions/functions, or by dropping calls to certain intrinsics (like debug intrinsics). I will implement support for inserting missing function/global declarations in a followup patch. We don't have real use lists for metadata, so the approach here is to iterate over the whole IR and identify metadata that needs to be dropped. This does not support all possible cases, but should handle anything that's relevant for the function-only IR use case.
1 parent de8f782 commit cc19416

File tree

9 files changed

+152
-15
lines changed

9 files changed

+152
-15
lines changed

llvm/include/llvm/AsmParser/LLParser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ namespace llvm {
328328

329329
// Top-Level Entities
330330
bool parseTopLevelEntities();
331+
void dropUnknownMetadataReferences();
331332
bool validateEndOfModule(bool UpgradeDebugInfo);
332333
bool validateEndOfIndex();
333334
bool parseTargetDefinitions(DataLayoutCallbackTy DataLayoutCallback);

llvm/include/llvm/IR/GlobalObject.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ class GlobalObject : public GlobalValue {
133133
using Value::addMetadata;
134134
using Value::clearMetadata;
135135
using Value::eraseMetadata;
136+
using Value::eraseMetadataIf;
136137
using Value::getAllMetadata;
137138
using Value::getMetadata;
138139
using Value::hasMetadata;

llvm/include/llvm/IR/Instruction.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,9 @@ class Instruction : public User,
384384
void copyMetadata(const Instruction &SrcInst,
385385
ArrayRef<unsigned> WL = ArrayRef<unsigned>());
386386

387+
/// Erase all metadata that matches the predicate.
388+
void eraseMetadataIf(function_ref<bool(unsigned, MDNode *)> Pred);
389+
387390
/// If the instruction has "branch_weights" MD_prof metadata and the MDNode
388391
/// has three operands (including name string), swap the order of the
389392
/// metadata.

llvm/include/llvm/IR/Metadata.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,8 @@ class ReplaceableMetadataImpl {
397397
/// is resolved.
398398
void resolveAllUses(bool ResolveUsers = true);
399399

400+
unsigned getNumUses() const { return UseMap.size(); }
401+
400402
private:
401403
void addRef(void *Ref, OwnerTy Owner);
402404
void dropRef(void *Ref);
@@ -1221,6 +1223,11 @@ class MDNode : public Metadata {
12211223

12221224
bool isReplaceable() const { return isTemporary(); }
12231225

1226+
unsigned getNumTemporaryUses() const {
1227+
assert(isTemporary() && "Only for temporaries");
1228+
return Context.getReplaceableUses()->getNumUses();
1229+
}
1230+
12241231
/// RAUW a temporary.
12251232
///
12261233
/// \pre \a isTemporary() must be \c true.

llvm/include/llvm/IR/Value.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,9 @@ class Value {
618618
/// \returns true if any metadata was removed.
619619
bool eraseMetadata(unsigned KindID);
620620

621+
/// Erase all metadata attachments matching the given predicate.
622+
void eraseMetadataIf(function_ref<bool(unsigned, MDNode *)> Pred);
623+
621624
/// Erase all metadata attached to this Value.
622625
void clearMetadata();
623626

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
#include "llvm/AsmParser/LLParser.h"
1414
#include "llvm/ADT/APSInt.h"
1515
#include "llvm/ADT/DenseMap.h"
16-
#include "llvm/ADT/ScopeExit.h"
1716
#include "llvm/ADT/STLExtras.h"
17+
#include "llvm/ADT/ScopeExit.h"
1818
#include "llvm/ADT/SmallPtrSet.h"
1919
#include "llvm/AsmParser/LLToken.h"
2020
#include "llvm/AsmParser/SlotMapping.h"
@@ -33,6 +33,7 @@
3333
#include "llvm/IR/GlobalObject.h"
3434
#include "llvm/IR/InlineAsm.h"
3535
#include "llvm/IR/Instructions.h"
36+
#include "llvm/IR/IntrinsicInst.h"
3637
#include "llvm/IR/Intrinsics.h"
3738
#include "llvm/IR/LLVMContext.h"
3839
#include "llvm/IR/Metadata.h"
@@ -54,6 +55,12 @@
5455

5556
using namespace llvm;
5657

58+
static cl::opt<bool> AllowIncompleteIR(
59+
"allow-incomplete-ir", cl::init(false), cl::Hidden,
60+
cl::desc(
61+
"Allow incomplete IR on a best effort basis (references to unknown "
62+
"metadata will be dropped)"));
63+
5764
static std::string getTypeString(Type *T) {
5865
std::string Result;
5966
raw_string_ostream Tmp(Result);
@@ -123,6 +130,57 @@ void LLParser::restoreParsingState(const SlotMapping *Slots) {
123130
std::make_pair(I.first, std::make_pair(I.second, LocTy())));
124131
}
125132

133+
void LLParser::dropUnknownMetadataReferences() {
134+
auto Pred = [](unsigned MDKind, MDNode *Node) { return Node->isTemporary(); };
135+
for (Function &F : *M) {
136+
F.eraseMetadataIf(Pred);
137+
for (BasicBlock &BB : F) {
138+
for (Instruction &I : make_early_inc_range(BB)) {
139+
I.eraseMetadataIf(Pred);
140+
141+
if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
142+
// If this is a white-listed intrinsic with an unknown metadata
143+
// operand, drop it.
144+
if (isa<DbgInfoIntrinsic>(II) ||
145+
II->getIntrinsicID() ==
146+
Intrinsic::experimental_noalias_scope_decl) {
147+
SmallVector<MetadataAsValue *> MVs;
148+
for (Value *V : II->args()) {
149+
if (auto *MV = dyn_cast<MetadataAsValue>(V))
150+
if (auto *MD = dyn_cast<MDNode>(MV->getMetadata()))
151+
if (MD->isTemporary())
152+
MVs.push_back(MV);
153+
}
154+
155+
if (!MVs.empty()) {
156+
assert(II->use_empty() && "Cannot have uses");
157+
II->eraseFromParent();
158+
159+
// Also remove no longer used MetadataAsValue wrappers.
160+
for (MetadataAsValue *MV : MVs) {
161+
if (MV->use_empty())
162+
delete MV;
163+
}
164+
}
165+
}
166+
}
167+
}
168+
}
169+
}
170+
171+
for (GlobalVariable &GV : M->globals())
172+
GV.eraseMetadataIf(Pred);
173+
174+
for (const auto &[ID, Info] : make_early_inc_range(ForwardRefMDNodes)) {
175+
// Check whether there is only a single use left, which would be in our
176+
// own NumberedMetadata.
177+
if (Info.first->getNumTemporaryUses() == 1) {
178+
NumberedMetadata.erase(ID);
179+
ForwardRefMDNodes.erase(ID);
180+
}
181+
}
182+
}
183+
126184
/// validateEndOfModule - Do final validity and basic correctness checks at the
127185
/// end of the module.
128186
bool LLParser::validateEndOfModule(bool UpgradeDebugInfo) {
@@ -256,6 +314,9 @@ bool LLParser::validateEndOfModule(bool UpgradeDebugInfo) {
256314
"use of undefined value '@" +
257315
Twine(ForwardRefValIDs.begin()->first) + "'");
258316

317+
if (AllowIncompleteIR && !ForwardRefMDNodes.empty())
318+
dropUnknownMetadataReferences();
319+
259320
if (!ForwardRefMDNodes.empty())
260321
return error(ForwardRefMDNodes.begin()->second.second,
261322
"use of undefined metadata '!" +
@@ -269,10 +330,14 @@ bool LLParser::validateEndOfModule(bool UpgradeDebugInfo) {
269330

270331
for (auto *Inst : InstsWithTBAATag) {
271332
MDNode *MD = Inst->getMetadata(LLVMContext::MD_tbaa);
272-
assert(MD && "UpgradeInstWithTBAATag should have a TBAA tag");
273-
auto *UpgradedMD = UpgradeTBAANode(*MD);
274-
if (MD != UpgradedMD)
275-
Inst->setMetadata(LLVMContext::MD_tbaa, UpgradedMD);
333+
// With incomplete IR, the tbaa metadata may have been dropped.
334+
if (!AllowIncompleteIR)
335+
assert(MD && "UpgradeInstWithTBAATag should have a TBAA tag");
336+
if (MD) {
337+
auto *UpgradedMD = UpgradeTBAANode(*MD);
338+
if (MD != UpgradedMD)
339+
Inst->setMetadata(LLVMContext::MD_tbaa, UpgradedMD);
340+
}
276341
}
277342

278343
// Look for intrinsic functions and CallInst that need to be upgraded. We use

llvm/lib/IR/Metadata.cpp

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,21 @@ bool Value::eraseMetadata(unsigned KindID) {
15061506
return Changed;
15071507
}
15081508

1509+
void Value::eraseMetadataIf(function_ref<bool(unsigned, MDNode *)> Pred) {
1510+
if (!HasMetadata)
1511+
return;
1512+
1513+
auto &MetadataStore = getContext().pImpl->ValueMetadata;
1514+
MDAttachments &Info = MetadataStore.find(this)->second;
1515+
assert(!Info.empty() && "bit out of sync with hash table");
1516+
Info.remove_if([Pred](const MDAttachments::Attachment &I) {
1517+
return Pred(I.MDKind, I.Node);
1518+
});
1519+
1520+
if (Info.empty())
1521+
clearMetadata();
1522+
}
1523+
15091524
void Value::clearMetadata() {
15101525
if (!HasMetadata)
15111526
return;
@@ -1529,6 +1544,13 @@ MDNode *Instruction::getMetadataImpl(StringRef Kind) const {
15291544
return Value::getMetadata(KindID);
15301545
}
15311546

1547+
void Instruction::eraseMetadataIf(function_ref<bool(unsigned, MDNode *)> Pred) {
1548+
if (DbgLoc && Pred(LLVMContext::MD_dbg, DbgLoc.getAsMDNode()))
1549+
DbgLoc = {};
1550+
1551+
Value::eraseMetadataIf(Pred);
1552+
}
1553+
15321554
void Instruction::dropUnknownNonDebugMetadata(ArrayRef<unsigned> KnownIDs) {
15331555
if (!Value::hasMetadata())
15341556
return; // Nothing to remove!
@@ -1539,17 +1561,9 @@ void Instruction::dropUnknownNonDebugMetadata(ArrayRef<unsigned> KnownIDs) {
15391561
// A DIAssignID attachment is debug metadata, don't drop it.
15401562
KnownSet.insert(LLVMContext::MD_DIAssignID);
15411563

1542-
auto &MetadataStore = getContext().pImpl->ValueMetadata;
1543-
MDAttachments &Info = MetadataStore.find(this)->second;
1544-
assert(!Info.empty() && "bit out of sync with hash table");
1545-
Info.remove_if([&KnownSet](const MDAttachments::Attachment &I) {
1546-
return !KnownSet.count(I.MDKind);
1564+
Value::eraseMetadataIf([&KnownSet](unsigned MDKind, MDNode *Node) {
1565+
return !KnownSet.count(MDKind);
15471566
});
1548-
1549-
if (Info.empty()) {
1550-
// Drop our entry at the store.
1551-
clearMetadata();
1552-
}
15531567
}
15541568

15551569
void Instruction::updateDIAssignIDMapping(DIAssignID *ID) {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
; RUN: not llvm-as -allow-incomplete-ir < %s 2>&1 | FileCheck %s
2+
3+
; CHECK: error: use of undefined metadata '!1'
4+
define void @test(ptr %p) {
5+
%v = load i8, ptr %p, !noalias !0
6+
ret void
7+
}
8+
9+
!0 = !{!1}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
2+
; RUN: opt -S -allow-incomplete-ir < %s | FileCheck %s
3+
4+
@g = global i8 0, !exclude !4
5+
6+
define void @test(ptr %p) !dbg !3 {
7+
; CHECK-LABEL: define void @test(
8+
; CHECK-SAME: ptr [[P:%.*]]) {
9+
; CHECK-NEXT: [[V1:%.*]] = load i8, ptr [[P]], align 1
10+
; CHECK-NEXT: [[V2:%.*]] = load i8, ptr [[P]], align 1
11+
; CHECK-NEXT: [[V3:%.*]] = load i8, ptr [[P]], align 1, !noalias [[META0:![0-9]+]]
12+
; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META0]])
13+
; CHECK-NEXT: ret void
14+
;
15+
%v1 = load i8, ptr %p, !noalias !0
16+
%v2 = load i8, ptr %p, !tbaa !1
17+
%v3 = load i8, ptr %p, !dbg !2, !noalias !100
18+
call void @llvm.experimental.noalias.scope.decl(metadata !5)
19+
call void @llvm.dbg.value(metadata i32 0, metadata !7, metadata !8)
20+
call void @llvm.experimental.noalias.scope.decl(metadata !100)
21+
ret void
22+
}
23+
24+
declare void @llvm.experimental.noalias.scope.decl(metadata)
25+
declare void @llvm.dbg.value(metadata, metadata, metadata)
26+
27+
!100 = !{!101}
28+
!101 = !{!101, !102}
29+
!102 = !{!102}
30+
;.
31+
; CHECK: [[META0]] = !{[[META1:![0-9]+]]}
32+
; CHECK: [[META1]] = distinct !{[[META1]], [[META2:![0-9]+]]}
33+
; CHECK: [[META2]] = distinct !{[[META2]]}
34+
;.

0 commit comments

Comments
 (0)