diff --git a/llvm/include/llvm/Analysis/DDG.h b/llvm/include/llvm/Analysis/DDG.h --- a/llvm/include/llvm/Analysis/DDG.h +++ b/llvm/include/llvm/Analysis/DDG.h @@ -104,6 +104,7 @@ /// Subclass of DDGNode representing single or multi-instruction nodes. class SimpleDDGNode : public DDGNode { + friend class DDGBuilder; public: SimpleDDGNode() = delete; SimpleDDGNode(Instruction &I); @@ -388,6 +389,12 @@ return PiNode->getNodes(); } + /// Return true if the two nodes \pSrc and \pTgt are both simple nodes and + /// the consecutive instructions after merging belong to the same basic block. + bool areMergeableNodes(const DDGNode &Src, + const DDGNode &Tgt) const final override; + void mergeNodes(DDGNode &Src, DDGNode &Tgt) final override; + bool shouldSimplify() const final override; bool shouldCreatePiBlocks() const final override; }; diff --git a/llvm/include/llvm/Analysis/DependenceGraphBuilder.h b/llvm/include/llvm/Analysis/DependenceGraphBuilder.h --- a/llvm/include/llvm/Analysis/DependenceGraphBuilder.h +++ b/llvm/include/llvm/Analysis/DependenceGraphBuilder.h @@ -58,6 +58,7 @@ createFineGrainedNodes(); createDefUseEdges(); createMemoryDependencyEdges(); + simplify(); createAndConnectRootNode(); createPiBlocks(); sortNodesTopologically(); @@ -92,6 +93,15 @@ /// the dependence graph into an acyclic graph. void createPiBlocks(); + /// Go through all the nodes in the graph and collapse any two nodes + /// 'a' and 'b' if all of the following are true: + /// - the only edge from 'a' is a def-use edge to 'b' and + /// - the only edge to 'b' is a def-use edge from 'a' and + /// - there is no cyclic edge from 'b' to 'a' and + /// - all instructions in 'a' and 'b' belong to the same basic block and + /// - both 'a' and 'b' are simple (single or multi instruction) nodes. + void simplify(); + /// Topologically sort the graph nodes. void sortNodesTopologically(); @@ -129,6 +139,17 @@ /// and false otherwise. virtual bool shouldCreatePiBlocks() const { return true; } + /// Return true if graph simplification step is requested, and false + /// otherwise. + virtual bool shouldSimplify() const { return true; } + + /// Return true if it's safe to merge the two nodes. + virtual bool areMergeableNodes(const NodeType &A, const NodeType &B) const = 0; + + /// Append the content of node \p B into node \p A and remove \p B and + /// the edge between \p A and \p B from the graph. + virtual void mergeNodes(NodeType &A, NodeType &B) = 0; + /// Given an instruction \p I return its associated ordinal number. size_t getOrdinal(Instruction &I) { assert(InstOrdinalMap.find(&I) != InstOrdinalMap.end() && diff --git a/llvm/lib/Analysis/DDG.cpp b/llvm/lib/Analysis/DDG.cpp --- a/llvm/lib/Analysis/DDG.cpp +++ b/llvm/lib/Analysis/DDG.cpp @@ -16,6 +16,11 @@ using namespace llvm; +static cl::opt SimplifyDDG( + "ddg-simplify", cl::init(true), cl::Hidden, cl::ZeroOrMore, + cl::desc( + "Simplify DDG by merging nodes that have less interesting edges.")); + static cl::opt CreatePiBlocks("ddg-pi-blocks", cl::init(true), cl::Hidden, cl::ZeroOrMore, cl::desc("Create pi-block nodes.")); @@ -257,6 +262,47 @@ return OS; } +//===--------------------------------------------------------------------===// +// DDGBuilder implementation +//===--------------------------------------------------------------------===// + +bool DDGBuilder::areMergeableNodes(const DDGNode &Src, + const DDGNode &Tgt) const { + // Only merge two nodes if they are both simple nodes and the consecutive + // instructions after merging belong to the same BB. + auto *SimpleSrc = dyn_cast(&Src); + auto *SimpleTgt = dyn_cast(&Tgt); + if (!SimpleSrc || !SimpleTgt) + return false; + + return SimpleSrc->getLastInstruction()->getParent() == + SimpleTgt->getFirstInstruction()->getParent(); +} + +void DDGBuilder::mergeNodes(DDGNode &A, DDGNode &B) { + DDGEdge &EdgeToFold = A.back(); + assert(A.getEdges().size() == 1 && EdgeToFold.getTargetNode() == B && + "Expected A to have a single edge to B."); + assert(isa(&A) && isa(&B) && + "Expected simple nodes"); + + // Copy instructions from B to the end of A. + cast(&A)->appendInstructions(*cast(&B)); + + // Move to A any outgoing edges from B. + for (DDGEdge *BE : B) + Graph.connect(A, BE->getTargetNode(), *BE); + + A.removeEdge(EdgeToFold); + destroyEdge(EdgeToFold); + Graph.removeNode(B); + destroyNode(B); +} + +bool DDGBuilder::shouldSimplify() const { + return SimplifyDDG; +} + bool DDGBuilder::shouldCreatePiBlocks() const { return CreatePiBlocks; } diff --git a/llvm/lib/Analysis/DependenceGraphBuilder.cpp b/llvm/lib/Analysis/DependenceGraphBuilder.cpp --- a/llvm/lib/Analysis/DependenceGraphBuilder.cpp +++ b/llvm/lib/Analysis/DependenceGraphBuilder.cpp @@ -374,6 +374,93 @@ } } +template void AbstractDependenceGraphBuilder::simplify() { + if (!shouldSimplify()) + return; + LLVM_DEBUG(dbgs() << "==== Start of Graph Simplification ===\n"); + + // First look for nodes that have a single outgoing def-use edge. + // Then look for target nodes that have a single incoming edge (the one + // coming from the source nodes identified in the previous step). We do this + // by counting the number of incoming edges for the nodes that are targets + // of the nodes identified above, and then excluding any candidate edge + // whose target has a count larger than one. + // This algorithm uses a map from the src node candidates to the + // number of incoming edges of the target node to which they are connected. + // For example if we have: + // a -> b + // c -> b + // d -> e + // then the map will eventually contain: {{a, 2}, {c, 2}, {d, 1}} + + DenseMap CandidateSrcNodes; + for (NodeType *N : Graph) { + if (N->getEdges().size() != 1) + continue; + if (!static_cast(N->back()).isDefUse()) + continue; + // Initialize the count to 0, and calculate later. + CandidateSrcNodes.insert({N, 0}); + } + + LLVM_DEBUG(dbgs() << "Size of candidate src node list:" + << CandidateSrcNodes.size() << "\n"; + for (auto &EC + : CandidateSrcNodes) { + dbgs() << "Node with single outgoing edge:" << EC.first << "\n"; + }); + + for (auto &EC : CandidateSrcNodes) { + assert(EC.first->getEdges().size() == 1 && + "Expected a single edge from the candidate src node."); + if (EC.second > 1) + continue; // stop counting if already more than one. + for (NodeType *N : Graph) + if (N->hasEdgeTo(EC.first->back().getTargetNode())) + ++EC.second; + } + + while (!CandidateSrcNodes.empty()) { + NodeType *Src = CandidateSrcNodes.begin()->first; + const bool TgtHasSingleIncomingEdge = CandidateSrcNodes[Src] == 1; + assert(Src->getEdges().size() == 1 && + "Expected a single edge from the candidate src node."); + + // Remove from the worklist. + CandidateSrcNodes.erase(Src); + + if (!TgtHasSingleIncomingEdge) + continue; + + NodeType &Tgt = Src->back().getTargetNode(); + if (!areMergeableNodes(*Src, Tgt)) + continue; + + // Do not merge if there is also an edge from target to src (immediate + // cycle). + if (Tgt.hasEdgeTo(*Src)) + continue; + + LLVM_DEBUG(dbgs() << "Merging:" << *Src << "\nWith:" << Tgt << "\n"); + + mergeNodes(*Src, Tgt); + + // The cancidate list is being used as both a worklist and a lookup table. + // If the target node is in the cancidate list itself, we need to put the + // src node back into the worklist again so it gives the target a chance + // to get merged into it. For example if we have: + // {(a)->(b), (b)->(c), (c)->(d)} and the worklist is initially {b, a}, + // then after merging (a) and (b) together, we need to put (a,b) back in + // the worklist so that (c) can get merged in as well resulting in + // {(a,b,c) -> d} + if (CandidateSrcNodes.find(&Tgt) != CandidateSrcNodes.end()) + CandidateSrcNodes.insert({Src, CandidateSrcNodes[&Tgt]}); + CandidateSrcNodes.erase(&Tgt); + } + + LLVM_DEBUG(dbgs() << "=== End of Graph Simplification ===\n"); +} + template void AbstractDependenceGraphBuilder::sortNodesTopologically() { diff --git a/llvm/test/Analysis/DDG/basic-a.ll b/llvm/test/Analysis/DDG/basic-a.ll --- a/llvm/test/Analysis/DDG/basic-a.ll +++ b/llvm/test/Analysis/DDG/basic-a.ll @@ -21,14 +21,9 @@ ; CHECK-NEXT: [def-use] to [[N4:0x[0-9a-f]*]] ; CHECK-NEXT: [def-use] to [[N5:0x[0-9a-f]*]] -; CHECK: Node Address:[[N5]]:single-instruction +; CHECK: Node Address:[[N5]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %exitcond = icmp ne i64 %inc, %n -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N6:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N6]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: br i1 %exitcond, label %test1.for.body, label %for.end.loopexit ; CHECK-NEXT: Edges:none! @@ -36,33 +31,28 @@ ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx1 = getelementptr inbounds float, float* %a, i64 %i.02 ; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N7:0x[0-9a-f]*]] +; CHECK-NEXT: [def-use] to [[N6:0x[0-9a-f]*]] -; CHECK: Node Address:[[N3]]:single-instruction +; CHECK: Node Address:[[N3]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx = getelementptr inbounds float, float* %b, i64 %i.02 -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N8:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N8]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: %0 = load float, float* %arrayidx, align 4 ; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N9:0x[0-9a-f]*]] +; CHECK-NEXT: [def-use] to [[N7:0x[0-9a-f]*]] -; CHECK: Node Address:[[N10:0x[0-9a-f]*]]:single-instruction +; CHECK: Node Address:[[N8:0x[0-9a-f]*]]:single-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %conv = uitofp i64 %n to float ; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N9]] +; CHECK-NEXT: [def-use] to [[N7]] -; CHECK: Node Address:[[N9]]:single-instruction +; CHECK: Node Address:[[N7]]:single-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %add = fadd float %0, %conv ; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N7]] +; CHECK-NEXT: [def-use] to [[N6]] -; CHECK: Node Address:[[N7]]:single-instruction +; CHECK: Node Address:[[N6]]:single-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: store float %add, float* %arrayidx1, align 4 ; CHECK-NEXT: Edges:none! @@ -118,14 +108,9 @@ ; CHECK-NEXT: [def-use] to [[N5:0x[0-9a-f]*]] ; CHECK-NEXT: [def-use] to [[N6:0x[0-9a-f]*]] -; CHECK: Node Address:[[N6]]:single-instruction +; CHECK: Node Address:[[N6]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %exitcond = icmp ne i64 %inc, %n -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N7:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N7]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: br i1 %exitcond, label %test2.for.body, label %for.end.loopexit ; CHECK-NEXT: Edges:none! @@ -133,40 +118,30 @@ ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx2 = getelementptr inbounds float, float* %a, i64 %i.02 ; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N8:0x[0-9a-f]*]] +; CHECK-NEXT: [def-use] to [[N7:0x[0-9a-f]*]] -; CHECK: Node Address:[[N4]]:single-instruction +; CHECK: Node Address:[[N4]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx1 = getelementptr inbounds float, float* %a, i64 %i.02 -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N9:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N9]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: %1 = load float, float* %arrayidx1, align 4 ; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N20:0x[0-9a-f]*]] -; CHECK-NEXT: [memory] to [[N8]] +; CHECK-NEXT: [def-use] to [[N8:0x[0-9a-f]*]] +; CHECK-NEXT: [memory] to [[N7]] -; CHECK: Node Address:[[N3]]:single-instruction +; CHECK: Node Address:[[N3]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx = getelementptr inbounds float, float* %b, i64 %i.02 -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N10:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N10]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: %0 = load float, float* %arrayidx, align 4 ; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N20]] +; CHECK-NEXT: [def-use] to [[N8]] -; CHECK: Node Address:[[N20]]:single-instruction +; CHECK: Node Address:[[N8]]:single-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %add = fadd float %0, %1 ; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N8]] +; CHECK-NEXT: [def-use] to [[N7]] -; CHECK: Node Address:[[N8]]:single-instruction +; CHECK: Node Address:[[N7]]:single-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: store float %add, float* %arrayidx2, align 4 ; CHECK-NEXT: Edges:none! diff --git a/llvm/test/Analysis/DDG/basic-b.ll b/llvm/test/Analysis/DDG/basic-b.ll --- a/llvm/test/Analysis/DDG/basic-b.ll +++ b/llvm/test/Analysis/DDG/basic-b.ll @@ -22,14 +22,9 @@ ; CHECK-NEXT: [def-use] to [[N6:0x[0-9a-f]*]] ; CHECK-NEXT: [def-use] to [[N7:0x[0-9a-f]*]] -; CHECK: Node Address:[[N7]]:single-instruction +; CHECK: Node Address:[[N7]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %cmp = icmp ult i64 %inc, %sub -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N8:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N8]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: br i1 %cmp, label %test1.for.body, label %for.end.loopexit ; CHECK-NEXT: Edges:none! @@ -37,51 +32,41 @@ ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx3 = getelementptr inbounds float, float* %a, i64 %i.02 ; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N9:0x[0-9a-f]*]] +; CHECK-NEXT: [def-use] to [[N8:0x[0-9a-f]*]] -; CHECK: Node Address:[[N5]]:single-instruction +; CHECK: Node Address:[[N5]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %sub1 = add i64 %i.02, -1 -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N10:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N10]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx2 = getelementptr inbounds float, float* %a, i64 %sub1 ; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N9]] +; CHECK-NEXT: [def-use] to [[N8]] -; CHECK: Node Address:[[N4]]:single-instruction +; CHECK: Node Address:[[N4]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx = getelementptr inbounds float, float* %b, i64 %i.02 -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N11:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N11]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: %0 = load float, float* %arrayidx, align 4 ; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N9]] +; CHECK-NEXT: [def-use] to [[N8]] -; CHECK: Node Address:[[N9]]:pi-block +; CHECK: Node Address:[[N8]]:pi-block ; CHECK-NEXT: --- start of nodes in pi-block --- -; CHECK: Node Address:[[N12:0x[0-9a-f]*]]:single-instruction +; CHECK: Node Address:[[N9:0x[0-9a-f]*]]:single-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %1 = load float, float* %arrayidx2, align 4 ; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N13:0x[0-9a-f]*]] +; CHECK-NEXT: [def-use] to [[N10:0x[0-9a-f]*]] -; CHECK: Node Address:[[N13]]:single-instruction +; CHECK: Node Address:[[N10]]:single-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %add = fadd float %0, %1 ; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N14:0x[0-9a-f]*]] +; CHECK-NEXT: [def-use] to [[N11:0x[0-9a-f]*]] -; CHECK: Node Address:[[N14]]:single-instruction +; CHECK: Node Address:[[N11]]:single-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: store float %add, float* %arrayidx3, align 4 ; CHECK-NEXT: Edges: -; CHECK-NEXT: [memory] to [[N12]] +; CHECK-NEXT: [memory] to [[N9]] ; CHECK-NEXT:--- end of nodes in pi-block --- ; CHECK-NEXT: Edges:none! @@ -141,14 +126,9 @@ ; CHECK-NEXT: [def-use] to [[N6:0x[0-9a-f]*]] ; CHECK-NEXT: [def-use] to [[N7:0x[0-9a-f]*]] -; CHECK: Node Address:[[N7]]:single-instruction +; CHECK: Node Address:[[N7]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %cmp = icmp ult i64 %inc, %sub -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N8:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N8]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: br i1 %cmp, label %test2.for.body, label %for.end.loopexit ; CHECK-NEXT: Edges:none! @@ -156,47 +136,31 @@ ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx3 = getelementptr inbounds float, float* %a, i64 %i.02 ; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N9:0x[0-9a-f]*]] +; CHECK-NEXT: [def-use] to [[N8:0x[0-9a-f]*]] -; CHECK: Node Address:[[N5]]:single-instruction +; CHECK: Node Address:[[N5]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %add1 = add i64 %i.02, 1 -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N10:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N10]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx2 = getelementptr inbounds float, float* %a, i64 %add1 -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N11:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N11]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: %1 = load float, float* %arrayidx2, align 4 ; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N12:0x[0-9a-f]*]] -; CHECK-NEXT: [memory] to [[N9]] +; CHECK-NEXT: [def-use] to [[N9:0x[0-9a-f]*]] +; CHECK-NEXT: [memory] to [[N8]] -; CHECK: Node Address:[[N4]]:single-instruction +; CHECK: Node Address:[[N4]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx = getelementptr inbounds float, float* %b, i64 %i.02 -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N13:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N13]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: %0 = load float, float* %arrayidx, align 4 ; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N12]] - +; CHECK-NEXT: [def-use] to [[N9]] -; CHECK: Node Address:[[N12]]:single-instruction +; CHECK: Node Address:[[N9]]:single-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %add = fadd float %0, %1 ; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N9]] +; CHECK-NEXT: [def-use] to [[N8]] -; CHECK: Node Address:[[N9]]:single-instruction +; CHECK: Node Address:[[N8]]:single-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: store float %add, float* %arrayidx3, align 4 ; CHECK-NEXT: Edges:none! diff --git a/llvm/test/Analysis/DDG/basic-loopnest.ll b/llvm/test/Analysis/DDG/basic-loopnest.ll --- a/llvm/test/Analysis/DDG/basic-loopnest.ll +++ b/llvm/test/Analysis/DDG/basic-loopnest.ll @@ -49,25 +49,15 @@ ; CHECK-NEXT: [def-use] to [[N14:0x[0-9a-f]*]] ; CHECK-NEXT: [def-use] to [[N15:0x[0-9a-f]*]] -; CHECK: Node Address:[[N15]]:single-instruction +; CHECK: Node Address:[[N15]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %exitcond = icmp ne i64 %inc13, %n -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N16:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N16]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: br i1 %exitcond, label %test1.for.cond1.preheader, label %for.end14.loopexit ; CHECK-NEXT: Edges:none! -; CHECK: Node Address:[[N14]]:single-instruction +; CHECK: Node Address:[[N14]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %4 = mul nsw i64 %i.04, %n -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N17:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N17]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx10 = getelementptr inbounds float, float* %a, i64 %4 ; CHECK-NEXT: Edges: ; CHECK-NEXT: [def-use] to [[N6]] @@ -78,14 +68,9 @@ ; CHECK-NEXT: Edges: ; CHECK-NEXT: [def-use] to [[N18:0x[0-9a-f]*]] -; CHECK: Node Address:[[N13]]:single-instruction +; CHECK: Node Address:[[N13]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %2 = mul nsw i64 %i.04, %n -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N19:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N19]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx6 = getelementptr inbounds float, float* %a, i64 %2 ; CHECK-NEXT: Edges: ; CHECK-NEXT: [def-use] to [[N8]] @@ -96,26 +81,16 @@ ; CHECK-NEXT: Edges: ; CHECK-NEXT: [def-use] to [[N18]] -; CHECK: Node Address:[[N12]]:single-instruction +; CHECK: Node Address:[[N12]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %0 = mul nsw i64 %i.04, %n -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N20:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N20]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx = getelementptr inbounds float, float* %b, i64 %0 ; CHECK-NEXT: Edges: ; CHECK-NEXT: [def-use] to [[N4]] -; CHECK: Node Address:[[N4]]:single-instruction +; CHECK: Node Address:[[N4]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx5 = getelementptr inbounds float, float* %arrayidx, i64 %j.02 -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N21:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N21]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: %1 = load float, float* %arrayidx5, align 4 ; CHECK-NEXT: Edges: ; CHECK-NEXT: [def-use] to [[N18]] @@ -159,25 +134,15 @@ ; CHECK-NEXT: [def-use] to [[N7]] ; CHECK-NEXT: [def-use] to [[N28:0x[0-9a-f]*]] -; CHECK: Node Address:[[N28]]:single-instruction +; CHECK: Node Address:[[N28]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %cmp21 = icmp ult i64 1, %sub -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N29:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N29]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: br i1 %cmp21, label %for.body4.preheader, label %for.inc12 ; CHECK-NEXT: Edges:none! -; CHECK: Node Address:[[N7]]:single-instruction +; CHECK: Node Address:[[N7]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %cmp2 = icmp ult i64 %inc, %sub -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N30:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N30]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: br i1 %cmp2, label %for.body4, label %for.inc12.loopexit ; CHECK-NEXT: Edges:none! @@ -279,25 +244,15 @@ ; CHECK-NEXT: [def-use] to [[N13:0x[0-9a-f]*]] ; CHECK-NEXT: [def-use] to [[N14:0x[0-9a-f]*]] -; CHECK: Node Address:[[N14]]:single-instruction +; CHECK: Node Address:[[N14]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %exitcond = icmp ne i64 %inc13, %n -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N15:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N15]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: br i1 %exitcond, label %test2.for.cond1.preheader, label %for.end14.loopexit ; CHECK-NEXT: Edges:none! -; CHECK: Node Address:[[N13]]:single-instruction +; CHECK: Node Address:[[N13]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %4 = mul nsw i64 %i.04, %n -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N16:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N16]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx10 = getelementptr inbounds float, float* %a, i64 %4 ; CHECK-NEXT: Edges: ; CHECK-NEXT: [def-use] to [[N5]] @@ -308,51 +263,31 @@ ; CHECK-NEXT: Edges: ; CHECK-NEXT: [def-use] to [[N17:0x[0-9a-f]*]] -; CHECK: Node Address:[[N12]]:single-instruction +; CHECK: Node Address:[[N12]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %2 = mul nsw i64 %i.04, %n -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N18:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N18]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx6 = getelementptr inbounds float, float* %a, i64 %2 ; CHECK-NEXT: Edges: ; CHECK-NEXT: [def-use] to [[N7]] -; CHECK: Node Address:[[N7]]:single-instruction +; CHECK: Node Address:[[N7]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx8 = getelementptr inbounds float, float* %arrayidx6, i64 %add7 -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N19:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N19]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: %3 = load float, float* %arrayidx8, align 4 ; CHECK-NEXT: Edges: ; CHECK-NEXT: [def-use] to [[N20:0x[0-9a-f]*]] ; CHECK-NEXT: [memory] to [[N17]] -; CHECK: Node Address:[[N11]]:single-instruction +; CHECK: Node Address:[[N11]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %0 = mul nsw i64 %i.04, %n -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N21:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N21]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx = getelementptr inbounds float, float* %b, i64 %0 ; CHECK-NEXT: Edges: ; CHECK-NEXT: [def-use] to [[N3]] -; CHECK: Node Address:[[N3]]:single-instruction +; CHECK: Node Address:[[N3]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %arrayidx5 = getelementptr inbounds float, float* %arrayidx, i64 %j.02 -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N22:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N22]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: %1 = load float, float* %arrayidx5, align 4 ; CHECK-NEXT: Edges: ; CHECK-NEXT: [def-use] to [[N20]] @@ -385,25 +320,15 @@ ; CHECK-NEXT: [def-use] to [[N6]] ; CHECK-NEXT: [def-use] to [[N26:0x[0-9a-f]*]] -; CHECK: Node Address:[[N26]]:single-instruction +; CHECK: Node Address:[[N26]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %cmp21 = icmp ult i64 1, %sub -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N27:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N27]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: br i1 %cmp21, label %for.body4.preheader, label %for.inc12 ; CHECK-NEXT: Edges:none! -; CHECK: Node Address:[[N6]]:single-instruction +; CHECK: Node Address:[[N6]]:multi-instruction ; CHECK-NEXT: Instructions: ; CHECK-NEXT: %cmp2 = icmp ult i64 %inc, %sub -; CHECK-NEXT: Edges: -; CHECK-NEXT: [def-use] to [[N28:0x[0-9a-f]*]] - -; CHECK: Node Address:[[N28]]:single-instruction -; CHECK-NEXT: Instructions: ; CHECK-NEXT: br i1 %cmp2, label %for.body4, label %for.inc12.loopexit ; CHECK-NEXT: Edges:none!