BitcodeWriter: Emit metadata in post-order (again)
Emit metadata nodes in post-order. The iterative algorithm from r266709
failed to maintain this property. After understanding my mistake, it
wasn't too hard to write a test with llvm-bcanalyzer (and I've actually
made this change once before: see r220340).
This also reverts the "noisy" testcase change from r266709. That should
have been more of a red flag :/.
Note: The same bug crept into the ValueMapper in r265456. I'm still
working on the fix.
llvm-svn: 266947
diff --git a/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp b/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp
index 9894029..7eb23f0 100644
--- a/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp
+++ b/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp
@@ -568,19 +568,23 @@
void ValueEnumerator::EnumerateMetadata(unsigned F, const Metadata *MD) {
// Start by enumerating MD, and then work through its transitive operands in
- // post-order.
- SmallVector<std::pair<const MDNode *, bool>, 32> Worklist;
+ // post-order. This requires a depth-first search.
+ SmallVector<std::pair<const MDNode *, const MDOperand *>, 32> Worklist;
enumerateMetadataImpl(F, MD, Worklist);
while (!Worklist.empty()) {
const MDNode *N = Worklist.back().first;
- if (!Worklist.back().second) {
- // On the first visit, add the operands to the worklist.
- Worklist.back().second = true;
- unsigned F = MetadataMap.lookup(N).F;
- for (const Metadata *Op : N->operands())
- enumerateMetadataImpl(F, Op, Worklist);
+ const MDOperand *&Op = Worklist.back().second; // Be careful of lifetime...
+
+ // Enumerate operands until the worklist changes. We need to traverse new
+ // nodes before visiting the rest of N's operands.
+ bool DidWorklistChange = false;
+ for (const MDOperand *E = N->op_end(); Op != E;)
+ if (enumerateMetadataImpl(F, *Op++, Worklist)) {
+ DidWorklistChange = true;
+ break;
+ }
+ if (DidWorklistChange)
continue;
- }
// All the operands have been visited. Now assign an ID.
Worklist.pop_back();
@@ -590,11 +594,11 @@
}
}
-void ValueEnumerator::enumerateMetadataImpl(
+bool ValueEnumerator::enumerateMetadataImpl(
unsigned F, const Metadata *MD,
- SmallVectorImpl<std::pair<const MDNode *, bool>> &Worklist) {
+ SmallVectorImpl<std::pair<const MDNode *, const MDOperand *>> &Worklist) {
if (!MD)
- return;
+ return false;
assert(
(isa<MDNode>(MD) || isa<MDString>(MD) || isa<ConstantAsMetadata>(MD)) &&
@@ -606,13 +610,13 @@
// Already mapped. If F doesn't match the function tag, drop it.
if (Entry.hasDifferentFunction(F))
dropFunctionFromMetadata(*Insertion.first);
- return;
+ return false;
}
// MDNodes are handled separately to avoid recursion.
if (auto *N = dyn_cast<MDNode>(MD)) {
- Worklist.push_back(std::make_pair(N, false));
- return;
+ Worklist.push_back(std::make_pair(N, N->op_begin()));
+ return true; // Changed the worklist.
}
// Save the metadata.
@@ -622,6 +626,8 @@
// Enumerate the constant, if any.
if (auto *C = dyn_cast<ConstantAsMetadata>(MD))
EnumerateValue(C->getValue());
+
+ return false;
}
/// EnumerateFunctionLocalMetadataa - Incorporate function-local metadata
diff --git a/llvm/lib/Bitcode/Writer/ValueEnumerator.h b/llvm/lib/Bitcode/Writer/ValueEnumerator.h
index 98e2df1..e858c7a 100644
--- a/llvm/lib/Bitcode/Writer/ValueEnumerator.h
+++ b/llvm/lib/Bitcode/Writer/ValueEnumerator.h
@@ -34,6 +34,7 @@
class Metadata;
class LocalAsMetadata;
class MDNode;
+class MDOperand;
class NamedMDNode;
class AttributeSet;
class ValueSymbolTable;
@@ -245,9 +246,9 @@
/// function.
void incorporateFunctionMetadata(const Function &F);
- void enumerateMetadataImpl(
+ bool enumerateMetadataImpl(
unsigned F, const Metadata *MD,
- SmallVectorImpl<std::pair<const MDNode *, bool>> &Worklist);
+ SmallVectorImpl<std::pair<const MDNode *, const MDOperand *>> &Worklist);
unsigned getMetadataFunctionID(const Function *F) const;
void EnumerateMetadata(const Function *F, const Metadata *MD);
diff --git a/llvm/test/Bitcode/mdnodes-in-post-order.ll b/llvm/test/Bitcode/mdnodes-in-post-order.ll
new file mode 100644
index 0000000..fbe1c34
--- /dev/null
+++ b/llvm/test/Bitcode/mdnodes-in-post-order.ll
@@ -0,0 +1,34 @@
+; RUN: llvm-as <%s | llvm-bcanalyzer -dump | FileCheck %s
+; Check that nodes are emitted in post-order to minimize the need for temporary
+; nodes. The graph structure is designed to foil naive implementations of
+; iteratitive post-order traersals: the leaves, !3 and !4, are reachable from
+; the entry node, !6, as well as from !5. There is one leaf on either side to
+; be sure it tickles bugs whether operands are visited forward or reverse.
+
+; Nodes in this testcase are numbered to match how they are referenced in
+; bitcode. !3 is referenced as opN=3.
+
+; We don't care about the order of the strings (or of !3 and !4). Let's just
+; make sure the strings are first and make it clear that there are two of them.
+; CHECK: <STRINGS {{.*}} num-strings = 2 {
+; CHECK-NEXT: 'leaf
+; CHECK-NEXT: 'leaf
+; CHECK-NEXT: }
+
+; The leafs should come first (in either order).
+; CHECK-NEXT: <NODE op0=1/>
+; CHECK-NEXT: <NODE op0=2/>
+!3 = !{!"leaf3"}
+!4 = !{!"leaf4"}
+
+; CHECK-NEXT: <NODE op0=3 op1=4/>
+!5 = !{!3, !4}
+
+; CHECK-NEXT: <NODE op0=3 op1=5 op2=4/>
+!6 = !{!3, !5, !4}
+
+; Note: named metadata nodes are not cannot reference null so their operands
+; are numbered off-by-one.
+; CHECK-NEXT: <NAME
+; CHECK-NEXT: <NAMED_NODE op0=5/>
+!named = !{!6}
diff --git a/llvm/test/Bitcode/metadata-function-blocks.ll b/llvm/test/Bitcode/metadata-function-blocks.ll
index 7b335f7..f3e83c5 100644
--- a/llvm/test/Bitcode/metadata-function-blocks.ll
+++ b/llvm/test/Bitcode/metadata-function-blocks.ll
@@ -19,14 +19,14 @@
; Each node gets a new number. Bottom-up traversal of nodes.
!named = !{!6}
-; CHECK-NEXT: <NODE op0=2/>
-!4 = !{!"named and foo"}
-
; CHECK-NEXT: <NODE op0=1/>
-!5 = !{!"named"}
+!4 = !{!"named"}
-; CHECK-NEXT: <NODE op0=1 op1=5 op2=4/>
-!6 = !{!"named", !5, !4}
+; CHECK-NEXT: <NODE op0=2/>
+!5 = !{!"named and foo"}
+
+; CHECK-NEXT: <NODE op0=1 op1=4 op2=5/>
+!6 = !{!"named", !4, !5}
; CHECK-NEXT: <NODE op0=3/>
!7 = !{!"foo and bar"}