llvm.org GIT mirror llvm / 3ab88a9
[LCG] Teach the ref edge removal to handle a ref edge that is trivial due to a call cycle. This actually crashed the ref removal before. I've added a unittest that covers this kind of interesting graph structure and mutation. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@290645 91177308-0d34-0410-b5e6-96231b3b80d8 Chandler Carruth 2 years ago
2 changed file(s) with 85 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
11161116 if (&SourceN == &TargetN)
11171117 return Result;
11181118
1119 // If this ref edge is within an SCC then there are sufficient other edges to
1120 // form a cycle without this edge so removing it is a no-op.
1121 SCC &SourceC = *G->lookupSCC(SourceN);
1122 SCC &TargetC = *G->lookupSCC(TargetN);
1123 if (&SourceC == &TargetC)
1124 return Result;
1125
11191126 // We build somewhat synthetic new RefSCCs by providing a postorder mapping
11201127 // for each inner SCC. We also store these associated with *nodes* rather
11211128 // than SCCs because this saves a round-trip through the node->SCC map and in
11381145 // and handle participants in that cycle without walking all the edges that
11391146 // form the connections, and instead by relying on the fundamental guarantee
11401147 // coming into this operation.
1141 SCC &TargetC = *G->lookupSCC(TargetN);
11421148 for (Node &N : TargetC)
11431149 PostOrderMapping[&N] = RootPostOrderNumber;
11441150
15991599 EXPECT_EQ(E, J);
16001600 }
16011601
1602 TEST(LazyCallGraphTest, InternalNoOpEdgeRemoval) {
1603 LLVMContext Context;
1604 // A graph with a single cycle formed both from call and reference edges
1605 // which makes the reference edges trivial to delete. The graph looks like:
1606 //
1607 // Reference edges: a -> b -> c -> a
1608 // Call edges: a -> c -> b -> a
1609 std::unique_ptr M = parseAssembly(
1610 Context, "define void @a(i8** %ptr) {\n"
1611 "entry:\n"
1612 " call void @b(i8** %ptr)\n"
1613 " store i8* bitcast (void(i8**)* @c to i8*), i8** %ptr\n"
1614 " ret void\n"
1615 "}\n"
1616 "define void @b(i8** %ptr) {\n"
1617 "entry:\n"
1618 " store i8* bitcast (void(i8**)* @a to i8*), i8** %ptr\n"
1619 " call void @c(i8** %ptr)\n"
1620 " ret void\n"
1621 "}\n"
1622 "define void @c(i8** %ptr) {\n"
1623 "entry:\n"
1624 " call void @a(i8** %ptr)\n"
1625 " store i8* bitcast (void(i8**)* @b to i8*), i8** %ptr\n"
1626 " ret void\n"
1627 "}\n");
1628 LazyCallGraph CG(*M);
1629
1630 // Force the graph to be fully expanded.
1631 auto I = CG.postorder_ref_scc_begin(), E = CG.postorder_ref_scc_end();
1632 LazyCallGraph::RefSCC &RC = *I;
1633 EXPECT_EQ(E, std::next(I));
1634
1635 LazyCallGraph::SCC &C = *RC.begin();
1636 EXPECT_EQ(RC.end(), std::next(RC.begin()));
1637
1638 LazyCallGraph::Node &AN = *CG.lookup(lookupFunction(*M, "a"));
1639 LazyCallGraph::Node &BN = *CG.lookup(lookupFunction(*M, "b"));
1640 LazyCallGraph::Node &CN = *CG.lookup(lookupFunction(*M, "c"));
1641 EXPECT_EQ(&RC, CG.lookupRefSCC(AN));
1642 EXPECT_EQ(&RC, CG.lookupRefSCC(BN));
1643 EXPECT_EQ(&RC, CG.lookupRefSCC(CN));
1644 EXPECT_EQ(&C, CG.lookupSCC(AN));
1645 EXPECT_EQ(&C, CG.lookupSCC(BN));
1646 EXPECT_EQ(&C, CG.lookupSCC(CN));
1647
1648 // Remove the edge from a -> c which doesn't change anything.
1649 SmallVector NewRCs =
1650 RC.removeInternalRefEdge(AN, CN);
1651 EXPECT_EQ(0u, NewRCs.size());
1652 EXPECT_EQ(&RC, CG.lookupRefSCC(AN));
1653 EXPECT_EQ(&RC, CG.lookupRefSCC(BN));
1654 EXPECT_EQ(&RC, CG.lookupRefSCC(CN));
1655 EXPECT_EQ(&C, CG.lookupSCC(AN));
1656 EXPECT_EQ(&C, CG.lookupSCC(BN));
1657 EXPECT_EQ(&C, CG.lookupSCC(CN));
1658 auto J = CG.postorder_ref_scc_begin();
1659 EXPECT_EQ(I, J);
1660 EXPECT_EQ(&RC, &*J);
1661 EXPECT_EQ(E, std::next(J));
1662
1663 // Remove the edge from b -> a and c -> b; again this doesn't change
1664 // anything.
1665 NewRCs = RC.removeInternalRefEdge(BN, AN);
1666 NewRCs = RC.removeInternalRefEdge(CN, BN);
1667 EXPECT_EQ(0u, NewRCs.size());
1668 EXPECT_EQ(&RC, CG.lookupRefSCC(AN));
1669 EXPECT_EQ(&RC, CG.lookupRefSCC(BN));
1670 EXPECT_EQ(&RC, CG.lookupRefSCC(CN));
1671 EXPECT_EQ(&C, CG.lookupSCC(AN));
1672 EXPECT_EQ(&C, CG.lookupSCC(BN));
1673 EXPECT_EQ(&C, CG.lookupSCC(CN));
1674 J = CG.postorder_ref_scc_begin();
1675 EXPECT_EQ(I, J);
1676 EXPECT_EQ(&RC, &*J);
1677 EXPECT_EQ(E, std::next(J));
1678 }
1679
16021680 TEST(LazyCallGraphTest, InternalCallEdgeToRef) {
16031681 LLVMContext Context;
16041682 // A nice fully connected (including self-edges) SCC (and RefSCC)