comparison llvm/unittests/Analysis/ScalarEvolutionTest.cpp @ 252:1f2b6ac9f198 llvm-original

LLVM16-1
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Fri, 18 Aug 2023 09:04:13 +0900
parents c4bab56944e8
children
comparison
equal deleted inserted replaced
237:c80f45b162ad 252:1f2b6ac9f198
56 ASSERT_NE(F, nullptr) << "Could not find " << FuncName; 56 ASSERT_NE(F, nullptr) << "Could not find " << FuncName;
57 ScalarEvolution SE = buildSE(*F); 57 ScalarEvolution SE = buildSE(*F);
58 Test(*F, *LI, SE); 58 Test(*F, *LI, SE);
59 } 59 }
60 60
61 static Optional<APInt> computeConstantDifference(ScalarEvolution &SE, 61 static std::optional<APInt> computeConstantDifference(ScalarEvolution &SE,
62 const SCEV *LHS, 62 const SCEV *LHS,
63 const SCEV *RHS) { 63 const SCEV *RHS) {
64 return SE.computeConstantDifference(LHS, RHS); 64 return SE.computeConstantDifference(LHS, RHS);
65 } 65 }
66 66
67 static bool matchURem(ScalarEvolution &SE, const SCEV *Expr, const SCEV *&LHS, 67 static bool matchURem(ScalarEvolution &SE, const SCEV *Expr, const SCEV *&LHS,
68 const SCEV *&RHS) { 68 const SCEV *&RHS) {
69 return SE.matchURem(Expr, LHS, RHS); 69 return SE.matchURem(Expr, LHS, RHS);
70 } 70 }
739 DataLayout += "-"; 739 DataLayout += "-";
740 DataLayout += "ni:10"; 740 DataLayout += "ni:10";
741 NIM.setDataLayout(DataLayout); 741 NIM.setDataLayout(DataLayout);
742 742
743 Type *T_int64 = Type::getInt64Ty(Context); 743 Type *T_int64 = Type::getInt64Ty(Context);
744 Type *T_pint64 = T_int64->getPointerTo(10); 744 Type *T_pint64 = PointerType::get(Context, 10);
745 745
746 FunctionType *FTy = 746 FunctionType *FTy =
747 FunctionType::get(Type::getVoidTy(Context), {T_pint64}, false); 747 FunctionType::get(Type::getVoidTy(Context), {T_pint64}, false);
748 Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", NIM); 748 Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", NIM);
749 749
837 DataLayout += "-"; 837 DataLayout += "-";
838 DataLayout += "ni:10"; 838 DataLayout += "ni:10";
839 NIM.setDataLayout(DataLayout); 839 NIM.setDataLayout(DataLayout);
840 840
841 Type *T_int64 = Type::getInt64Ty(Context); 841 Type *T_int64 = Type::getInt64Ty(Context);
842 Type *T_pint64 = T_int64->getPointerTo(10); 842 Type *T_pint64 = PointerType::get(Context, 10);
843 843
844 FunctionType *FTy = 844 FunctionType *FTy =
845 FunctionType::get(Type::getVoidTy(Context), {T_pint64}, false); 845 FunctionType::get(Type::getVoidTy(Context), {T_pint64}, false);
846 Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", NIM); 846 Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", NIM);
847 847
1146 auto *ScevXA = SE.getSCEV(getInstructionByName(F, "xa")); // {%pp,+,1} 1146 auto *ScevXA = SE.getSCEV(getInstructionByName(F, "xa")); // {%pp,+,1}
1147 auto *ScevYY = SE.getSCEV(getInstructionByName(F, "yy")); // {(3 + %pp),+,1} 1147 auto *ScevYY = SE.getSCEV(getInstructionByName(F, "yy")); // {(3 + %pp),+,1}
1148 auto *ScevXB = SE.getSCEV(getInstructionByName(F, "xb")); // {%pp,+,1} 1148 auto *ScevXB = SE.getSCEV(getInstructionByName(F, "xb")); // {%pp,+,1}
1149 auto *ScevIVNext = SE.getSCEV(getInstructionByName(F, "iv.next")); // {1,+,1} 1149 auto *ScevIVNext = SE.getSCEV(getInstructionByName(F, "iv.next")); // {1,+,1}
1150 1150
1151 auto diff = [&SE](const SCEV *LHS, const SCEV *RHS) -> Optional<int> { 1151 auto diff = [&SE](const SCEV *LHS, const SCEV *RHS) -> std::optional<int> {
1152 auto ConstantDiffOrNone = computeConstantDifference(SE, LHS, RHS); 1152 auto ConstantDiffOrNone = computeConstantDifference(SE, LHS, RHS);
1153 if (!ConstantDiffOrNone) 1153 if (!ConstantDiffOrNone)
1154 return None; 1154 return std::nullopt;
1155 1155
1156 auto ExtDiff = ConstantDiffOrNone->getSExtValue(); 1156 auto ExtDiff = ConstantDiffOrNone->getSExtValue();
1157 int Diff = ExtDiff; 1157 int Diff = ExtDiff;
1158 assert(Diff == ExtDiff && "Integer overflow"); 1158 assert(Diff == ExtDiff && "Integer overflow");
1159 return Diff; 1159 return Diff;
1168 EXPECT_EQ(diff(ScevXA, ScevYY), -3); 1168 EXPECT_EQ(diff(ScevXA, ScevYY), -3);
1169 EXPECT_EQ(diff(ScevYY, ScevXB), 3); 1169 EXPECT_EQ(diff(ScevYY, ScevXB), 3);
1170 EXPECT_EQ(diff(ScevIV, ScevIVNext), -1); 1170 EXPECT_EQ(diff(ScevIV, ScevIVNext), -1);
1171 EXPECT_EQ(diff(ScevIVNext, ScevIV), 1); 1171 EXPECT_EQ(diff(ScevIVNext, ScevIV), 1);
1172 EXPECT_EQ(diff(ScevIVNext, ScevIVNext), 0); 1172 EXPECT_EQ(diff(ScevIVNext, ScevIVNext), 0);
1173 EXPECT_EQ(diff(ScevV0, ScevIV), None); 1173 EXPECT_EQ(diff(ScevV0, ScevIV), std::nullopt);
1174 EXPECT_EQ(diff(ScevIVNext, ScevV3), None); 1174 EXPECT_EQ(diff(ScevIVNext, ScevV3), std::nullopt);
1175 EXPECT_EQ(diff(ScevYY, ScevV3), None); 1175 EXPECT_EQ(diff(ScevYY, ScevV3), std::nullopt);
1176 }); 1176 });
1177 } 1177 }
1178 1178
1179 TEST_F(ScalarEvolutionsTest, SCEVrewriteUnknowns) { 1179 TEST_F(ScalarEvolutionsTest, SCEVrewriteUnknowns) {
1180 LLVMContext C; 1180 LLVMContext C;
1534 ASSERT_TRUE(CeilingS->getAPInt() == CeilingInt); 1534 ASSERT_TRUE(CeilingS->getAPInt() == CeilingInt);
1535 } 1535 }
1536 }); 1536 });
1537 } 1537 }
1538 1538
1539 TEST_F(ScalarEvolutionsTest, ComputeMaxTripCountFromArrayNormal) { 1539 TEST_F(ScalarEvolutionsTest, CheckGetPowerOfTwo) {
1540 Module M("CheckGetPowerOfTwo", Context);
1541 FunctionType *FTy = FunctionType::get(Type::getVoidTy(Context), {}, false);
1542 Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", M);
1543 BasicBlock *Entry = BasicBlock::Create(Context, "entry", F);
1544 IRBuilder<> Builder(Entry);
1545 Builder.CreateRetVoid();
1546 ScalarEvolution SE = buildSE(*F);
1547
1548 for (unsigned short i = 0; i < 64; ++i)
1549 EXPECT_TRUE(
1550 dyn_cast<SCEVConstant>(SE.getPowerOfTwo(Type::getInt64Ty(Context), i))
1551 ->getValue()
1552 ->equalsInt(1ULL << i));
1553 }
1554
1555 TEST_F(ScalarEvolutionsTest, ApplyLoopGuards) {
1540 LLVMContext C; 1556 LLVMContext C;
1541 SMDiagnostic Err; 1557 SMDiagnostic Err;
1542 std::unique_ptr<Module> M = parseAssemblyString( 1558 std::unique_ptr<Module> M = parseAssemblyString(
1543 "define void @foo(i32 signext %len) { " 1559 "declare void @llvm.assume(i1)\n"
1544 "entry: " 1560 "define void @test(i32 %num) {\n"
1545 " %a = alloca [7 x i32], align 4 " 1561 "entry:\n"
1546 " %cmp4 = icmp sgt i32 %len, 0 " 1562 " %u = urem i32 %num, 4\n"
1547 " br i1 %cmp4, label %for.body.preheader, label %for.cond.cleanup " 1563 " %cmp = icmp eq i32 %u, 0\n"
1548 "for.body.preheader: " 1564 " tail call void @llvm.assume(i1 %cmp)\n"
1549 " br label %for.body " 1565 " %cmp.1 = icmp ugt i32 %num, 0\n"
1550 "for.cond.cleanup.loopexit: " 1566 " tail call void @llvm.assume(i1 %cmp.1)\n"
1551 " br label %for.cond.cleanup " 1567 " br label %for.body\n"
1552 "for.cond.cleanup: " 1568 "for.body:\n"
1553 " ret void " 1569 " %i.010 = phi i32 [ 0, %entry ], [ %inc, %for.body ]\n"
1554 "for.body: " 1570 " %inc = add nuw nsw i32 %i.010, 1\n"
1555 " %iv = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ] " 1571 " %cmp2 = icmp ult i32 %inc, %num\n"
1556 " %idxprom = zext i32 %iv to i64 " 1572 " br i1 %cmp2, label %for.body, label %exit\n"
1557 " %arrayidx = getelementptr inbounds [7 x i32], [7 x i32]* %a, i64 0, \ 1573 "exit:\n"
1558 i64 %idxprom " 1574 " ret void\n"
1559 " store i32 0, i32* %arrayidx, align 4 " 1575 "}\n",
1560 " %inc = add nuw nsw i32 %iv, 1 "
1561 " %cmp = icmp slt i32 %inc, %len "
1562 " br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit "
1563 "} ",
1564 Err, C); 1576 Err, C);
1565 1577
1566 ASSERT_TRUE(M && "Could not parse module?"); 1578 ASSERT_TRUE(M && "Could not parse module?");
1567 ASSERT_TRUE(!verifyModule(*M) && "Must have been well formed!"); 1579 ASSERT_TRUE(!verifyModule(*M) && "Must have been well formed!");
1568 1580
1569 runWithSE(*M, "foo", [](Function &F, LoopInfo &LI, ScalarEvolution &SE) { 1581 runWithSE(*M, "test", [](Function &F, LoopInfo &LI, ScalarEvolution &SE) {
1570 auto *ScevIV = SE.getSCEV(getInstructionByName(F, "iv")); 1582 auto *TCScev = SE.getSCEV(getArgByName(F, "num"));
1571 const Loop *L = cast<SCEVAddRecExpr>(ScevIV)->getLoop(); 1583 auto *ApplyLoopGuardsTC = SE.applyLoopGuards(TCScev, *LI.begin());
1572 1584 // Assert that the new TC is (4 * ((4 umax %num) /u 4))
1573 const SCEV *ITC = SE.getConstantMaxTripCountFromArray(L); 1585 APInt Four(32, 4);
1574 EXPECT_FALSE(isa<SCEVCouldNotCompute>(ITC)); 1586 auto *Constant4 = SE.getConstant(Four);
1575 EXPECT_TRUE(isa<SCEVConstant>(ITC)); 1587 auto *Max = SE.getUMaxExpr(TCScev, Constant4);
1576 EXPECT_EQ(cast<SCEVConstant>(ITC)->getAPInt().getSExtValue(), 8); 1588 auto *Mul = SE.getMulExpr(SE.getUDivExpr(Max, Constant4), Constant4);
1589 ASSERT_TRUE(Mul == ApplyLoopGuardsTC);
1577 }); 1590 });
1578 } 1591 }
1579 1592
1580 TEST_F(ScalarEvolutionsTest, ComputeMaxTripCountFromZeroArray) {
1581 LLVMContext C;
1582 SMDiagnostic Err;
1583 std::unique_ptr<Module> M = parseAssemblyString(
1584 "define void @foo(i32 signext %len) { "
1585 "entry: "
1586 " %a = alloca [0 x i32], align 4 "
1587 " %cmp4 = icmp sgt i32 %len, 0 "
1588 " br i1 %cmp4, label %for.body.preheader, label %for.cond.cleanup "
1589 "for.body.preheader: "
1590 " br label %for.body "
1591 "for.cond.cleanup.loopexit: "
1592 " br label %for.cond.cleanup "
1593 "for.cond.cleanup: "
1594 " ret void "
1595 "for.body: "
1596 " %iv = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ] "
1597 " %idxprom = zext i32 %iv to i64 "
1598 " %arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* %a, i64 0, \
1599 i64 %idxprom "
1600 " store i32 0, i32* %arrayidx, align 4 "
1601 " %inc = add nuw nsw i32 %iv, 1 "
1602 " %cmp = icmp slt i32 %inc, %len "
1603 " br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit "
1604 "} ",
1605 Err, C);
1606
1607 ASSERT_TRUE(M && "Could not parse module?");
1608 ASSERT_TRUE(!verifyModule(*M) && "Must have been well formed!");
1609
1610 runWithSE(*M, "foo", [](Function &F, LoopInfo &LI, ScalarEvolution &SE) {
1611 auto *ScevIV = SE.getSCEV(getInstructionByName(F, "iv"));
1612 const Loop *L = cast<SCEVAddRecExpr>(ScevIV)->getLoop();
1613
1614 const SCEV *ITC = SE.getConstantMaxTripCountFromArray(L);
1615 EXPECT_FALSE(isa<SCEVCouldNotCompute>(ITC));
1616 EXPECT_TRUE(isa<SCEVConstant>(ITC));
1617 EXPECT_EQ(cast<SCEVConstant>(ITC)->getAPInt().getSExtValue(), 1);
1618 });
1619 }
1620
1621 TEST_F(ScalarEvolutionsTest, ComputeMaxTripCountFromExtremArray) {
1622 LLVMContext C;
1623 SMDiagnostic Err;
1624 std::unique_ptr<Module> M = parseAssemblyString(
1625 "define void @foo(i32 signext %len) { "
1626 "entry: "
1627 " %a = alloca [4294967295 x i1], align 4 "
1628 " %cmp4 = icmp sgt i32 %len, 0 "
1629 " br i1 %cmp4, label %for.body.preheader, label %for.cond.cleanup "
1630 "for.body.preheader: "
1631 " br label %for.body "
1632 "for.cond.cleanup.loopexit: "
1633 " br label %for.cond.cleanup "
1634 "for.cond.cleanup: "
1635 " ret void "
1636 "for.body: "
1637 " %iv = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ] "
1638 " %idxprom = zext i32 %iv to i64 "
1639 " %arrayidx = getelementptr inbounds [4294967295 x i1], \
1640 [4294967295 x i1]* %a, i64 0, i64 %idxprom "
1641 " store i1 0, i1* %arrayidx, align 4 "
1642 " %inc = add nuw nsw i32 %iv, 1 "
1643 " %cmp = icmp slt i32 %inc, %len "
1644 " br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit "
1645 "} ",
1646 Err, C);
1647
1648 ASSERT_TRUE(M && "Could not parse module?");
1649 ASSERT_TRUE(!verifyModule(*M) && "Must have been well formed!");
1650
1651 runWithSE(*M, "foo", [](Function &F, LoopInfo &LI, ScalarEvolution &SE) {
1652 auto *ScevIV = SE.getSCEV(getInstructionByName(F, "iv"));
1653 const Loop *L = cast<SCEVAddRecExpr>(ScevIV)->getLoop();
1654
1655 const SCEV *ITC = SE.getConstantMaxTripCountFromArray(L);
1656 EXPECT_TRUE(isa<SCEVCouldNotCompute>(ITC));
1657 });
1658 }
1659
1660 TEST_F(ScalarEvolutionsTest, ComputeMaxTripCountFromArrayInBranch) {
1661 LLVMContext C;
1662 SMDiagnostic Err;
1663 std::unique_ptr<Module> M = parseAssemblyString(
1664 "define void @foo(i32 signext %len) { "
1665 "entry: "
1666 " %a = alloca [8 x i32], align 4 "
1667 " br label %for.cond "
1668 "for.cond: "
1669 " %iv = phi i32 [ %inc, %for.inc ], [ 0, %entry ] "
1670 " %cmp = icmp slt i32 %iv, %len "
1671 " br i1 %cmp, label %for.body, label %for.cond.cleanup "
1672 "for.cond.cleanup: "
1673 " br label %for.end "
1674 "for.body: "
1675 " %cmp1 = icmp slt i32 %iv, 8 "
1676 " br i1 %cmp1, label %if.then, label %if.end "
1677 "if.then: "
1678 " %idxprom = sext i32 %iv to i64 "
1679 " %arrayidx = getelementptr inbounds [8 x i32], [8 x i32]* %a, i64 0, \
1680 i64 %idxprom "
1681 " store i32 0, i32* %arrayidx, align 4 "
1682 " br label %if.end "
1683 "if.end: "
1684 " br label %for.inc "
1685 "for.inc: "
1686 " %inc = add nsw i32 %iv, 1 "
1687 " br label %for.cond "
1688 "for.end: "
1689 " ret void "
1690 "} ",
1691 Err, C);
1692
1693 ASSERT_TRUE(M && "Could not parse module?");
1694 ASSERT_TRUE(!verifyModule(*M) && "Must have been well formed!");
1695
1696 runWithSE(*M, "foo", [](Function &F, LoopInfo &LI, ScalarEvolution &SE) {
1697 auto *ScevIV = SE.getSCEV(getInstructionByName(F, "iv"));
1698 const Loop *L = cast<SCEVAddRecExpr>(ScevIV)->getLoop();
1699
1700 const SCEV *ITC = SE.getConstantMaxTripCountFromArray(L);
1701 EXPECT_TRUE(isa<SCEVCouldNotCompute>(ITC));
1702 });
1703 }
1704
1705 TEST_F(ScalarEvolutionsTest, ComputeMaxTripCountFromMultiDemArray) {
1706 LLVMContext C;
1707 SMDiagnostic Err;
1708 std::unique_ptr<Module> M = parseAssemblyString(
1709 "define void @foo(i32 signext %len) { "
1710 "entry: "
1711 " %a = alloca [3 x [5 x i32]], align 4 "
1712 " br label %for.cond "
1713 "for.cond: "
1714 " %iv = phi i32 [ %inc, %for.inc ], [ 0, %entry ] "
1715 " %cmp = icmp slt i32 %iv, %len "
1716 " br i1 %cmp, label %for.body, label %for.cond.cleanup "
1717 "for.cond.cleanup: "
1718 " br label %for.end "
1719 "for.body: "
1720 " %arrayidx = getelementptr inbounds [3 x [5 x i32]], \
1721 [3 x [5 x i32]]* %a, i64 0, i64 3 "
1722 " %idxprom = sext i32 %iv to i64 "
1723 " %arrayidx1 = getelementptr inbounds [5 x i32], [5 x i32]* %arrayidx, \
1724 i64 0, i64 %idxprom "
1725 " store i32 0, i32* %arrayidx1, align 4"
1726 " br label %for.inc "
1727 "for.inc: "
1728 " %inc = add nsw i32 %iv, 1 "
1729 " br label %for.cond "
1730 "for.end: "
1731 " ret void "
1732 "} ",
1733 Err, C);
1734
1735 ASSERT_TRUE(M && "Could not parse module?");
1736 ASSERT_TRUE(!verifyModule(*M) && "Must have been well formed!");
1737
1738 runWithSE(*M, "foo", [](Function &F, LoopInfo &LI, ScalarEvolution &SE) {
1739 auto *ScevIV = SE.getSCEV(getInstructionByName(F, "iv"));
1740 const Loop *L = cast<SCEVAddRecExpr>(ScevIV)->getLoop();
1741
1742 const SCEV *ITC = SE.getConstantMaxTripCountFromArray(L);
1743 EXPECT_TRUE(isa<SCEVCouldNotCompute>(ITC));
1744 });
1745 }
1746
1747 } // end namespace llvm 1593 } // end namespace llvm