Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit 29fa04d

Browse files
committed
BitcodeWriter: Emit uniqued subgraphs after all distinct nodes
Since forward references for uniqued node operands are expensive (and those for distinct node operands are cheap due to DistinctMDOperandPlaceholder), minimize forward references in uniqued node operands. Moreover, guarantee that when a cycle is broken by a distinct node, none of the uniqued nodes have any forward references. In ValueEnumerator::EnumerateMetadata, enumerate uniqued node subgraphs first, delaying distinct nodes until all uniqued nodes have been handled. This guarantees that uniqued nodes only have forward references when there is a uniquing cycle (since r267276 changed ValueEnumerator::organizeMetadata to partition distinct nodes in front of uniqued nodes as a post-pass). Note that a single uniqued subgraph can hit multiple distinct nodes at its leaves. Ideally these would themselves be emitted in post-order, but this commit doesn't attempt that; I think it requires an extra pass through the edges, which I'm not convinced is worth it (since DistinctMDOperandPlaceholder makes forward references quite cheap between distinct nodes). I've added two testcases: - test/Bitcode/mdnodes-distinct-in-post-order.ll is just like test/Bitcode/mdnodes-in-post-order.ll, except with distinct nodes instead of uniqued ones. This confirms that, in the absence of uniqued nodes, distinct nodes are still emitted in post-order. - test/Bitcode/mdnodes-distinct-nodes-break-cycles.ll is the minimal example where a naive post-order traversal would cause one uniqued node to forward-reference another. IOW, it's the motivating test. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@267278 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent f2d5595 commit 29fa04d

File tree

4 files changed

+91
-1
lines changed

4 files changed

+91
-1
lines changed

lib/Bitcode/Writer/ValueEnumerator.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,12 @@ void ValueEnumerator::dropFunctionFromMetadata(
567567
}
568568

569569
void ValueEnumerator::EnumerateMetadata(unsigned F, const Metadata *MD) {
570+
// It's vital for reader efficiency that uniqued subgraphs are done in
571+
// post-order; it's expensive when their operands have forward references.
572+
// If a distinct node is referenced from a uniqued node, it'll be delayed
573+
// until the uniqued subgraph has been completely traversed.
574+
SmallVector<const MDNode *, 32> DelayedDistinctNodes;
575+
570576
// Start by enumerating MD, and then work through its transitive operands in
571577
// post-order. This requires a depth-first search.
572578
SmallVector<std::pair<const MDNode *, MDNode::op_iterator>, 32> Worklist;
@@ -584,14 +590,27 @@ void ValueEnumerator::EnumerateMetadata(unsigned F, const Metadata *MD) {
584590
if (I != N->op_end()) {
585591
auto *Op = cast<MDNode>(*I);
586592
Worklist.back().second = ++I;
587-
Worklist.push_back(std::make_pair(Op, Op->op_begin()));
593+
594+
// Delay traversing Op if it's a distinct node and N is uniqued.
595+
if (Op->isDistinct() && !N->isDistinct())
596+
DelayedDistinctNodes.push_back(Op);
597+
else
598+
Worklist.push_back(std::make_pair(Op, Op->op_begin()));
588599
continue;
589600
}
590601

591602
// All the operands have been visited. Now assign an ID.
592603
Worklist.pop_back();
593604
MDs.push_back(N);
594605
MetadataMap[N].ID = MDs.size();
606+
607+
// Flush out any delayed distinct nodes; these are all the distinct nodes
608+
// that are leaves in last uniqued subgraph.
609+
if (Worklist.empty() || Worklist.back().first->isDistinct()) {
610+
for (const MDNode *N : DelayedDistinctNodes)
611+
Worklist.push_back(std::make_pair(N, N->op_begin()));
612+
DelayedDistinctNodes.clear();
613+
}
595614
}
596615
}
597616

lib/Bitcode/Writer/ValueEnumerator.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,26 @@ class ValueEnumerator {
256256
const MDNode *enumerateMetadataImpl(unsigned F, const Metadata *MD);
257257

258258
unsigned getMetadataFunctionID(const Function *F) const;
259+
260+
/// Enumerate reachable metadata in (almost) post-order.
261+
///
262+
/// Enumerate all the metadata reachable from MD. We want to minimize the
263+
/// cost of reading bitcode records, and so the primary consideration is that
264+
/// operands of uniqued nodes are resolved before the nodes are read. This
265+
/// avoids re-uniquing them on the context and factors away RAUW support.
266+
///
267+
/// This algorithm guarantees that subgraphs of uniqued nodes are in
268+
/// post-order. Distinct subgraphs reachable only from a single uniqued node
269+
/// will be in post-order.
270+
///
271+
/// \note The relative order of a distinct and uniqued node is irrelevant.
272+
/// \a organizeMetadata() will later partition distinct nodes ahead of
273+
/// uniqued ones.
274+
///{
259275
void EnumerateMetadata(const Function *F, const Metadata *MD);
260276
void EnumerateMetadata(unsigned F, const Metadata *MD);
277+
///}
278+
261279
void EnumerateFunctionLocalMetadata(const Function &F,
262280
const LocalAsMetadata *Local);
263281
void EnumerateFunctionLocalMetadata(unsigned F, const LocalAsMetadata *Local);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
; RUN: llvm-as <%s | llvm-bcanalyzer -dump | FileCheck %s
2+
; Check that distinct nodes are emitted in post-order to avoid unnecessary
3+
; forward references.
4+
5+
; Nodes in this testcase are numbered to match how they are referenced in
6+
; bitcode. !3 is referenced as opN=3.
7+
8+
; The leafs should come first (in either order).
9+
; CHECK: <DISTINCT_NODE/>
10+
; CHECK-NEXT: <DISTINCT_NODE/>
11+
!1 = distinct !{}
12+
!2 = distinct !{}
13+
14+
; CHECK-NEXT: <DISTINCT_NODE op0=1 op1=2/>
15+
!3 = distinct !{!1, !2}
16+
17+
; CHECK-NEXT: <DISTINCT_NODE op0=1 op1=3 op2=2/>
18+
!4 = distinct !{!1, !3, !2}
19+
20+
; Note: named metadata nodes are not cannot reference null so their operands
21+
; are numbered off-by-one.
22+
; CHECK-NEXT: <NAME
23+
; CHECK-NEXT: <NAMED_NODE op0=3/>
24+
!named = !{!4}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
; RUN: llvm-as <%s | llvm-bcanalyzer -dump | FileCheck %s
2+
; Check that distinct nodes break uniquing cycles, so that uniqued subgraphs
3+
; are always in post-order.
4+
;
5+
; It may not be immediately obvious why this is an interesting graph. There
6+
; are three nodes in a cycle, and one of them (!1) is distinct. Because the
7+
; entry point is !2, a naive post-order traversal would give !3, !1, !2; but
8+
; this means when !3 is parsed the reader will need a forward reference for !2.
9+
; Forward references for uniqued node operands are expensive, whereas they're
10+
; cheap for distinct node operands. If the distinct node is emitted first, the
11+
; uniqued nodes don't need any forward references at all.
12+
13+
; Nodes in this testcase are numbered to match how they are referenced in
14+
; bitcode. !3 is referenced as opN=3.
15+
16+
; CHECK: <DISTINCT_NODE op0=3/>
17+
!1 = distinct !{!3}
18+
19+
; CHECK-NEXT: <NODE op0=1/>
20+
!2 = !{!1}
21+
22+
; CHECK-NEXT: <NODE op0=2/>
23+
!3 = !{!2}
24+
25+
; Note: named metadata nodes are not cannot reference null so their operands
26+
; are numbered off-by-one.
27+
; CHECK-NEXT: <NAME
28+
; CHECK-NEXT: <NAMED_NODE op0=1/>
29+
!named = !{!2}

0 commit comments

Comments
 (0)