12f6987baSFedor Sergeev //===- LoopRotationUtilsTest.cpp - Unit tests for LoopRotation utility ----===// 22f6987baSFedor Sergeev // 32f6987baSFedor Sergeev // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42f6987baSFedor Sergeev // See https://llvm.org/LICENSE.txt for license information. 52f6987baSFedor Sergeev // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 62f6987baSFedor Sergeev // 72f6987baSFedor Sergeev //===----------------------------------------------------------------------===// 82f6987baSFedor Sergeev 92f6987baSFedor Sergeev #include "llvm/Transforms/Utils/LoopRotationUtils.h" 102f6987baSFedor Sergeev #include "llvm/Analysis/AssumptionCache.h" 112f6987baSFedor Sergeev #include "llvm/Analysis/InstructionSimplify.h" 122f6987baSFedor Sergeev #include "llvm/Analysis/LoopInfo.h" 132f6987baSFedor Sergeev #include "llvm/Analysis/ScalarEvolution.h" 142f6987baSFedor Sergeev #include "llvm/Analysis/TargetLibraryInfo.h" 152f6987baSFedor Sergeev #include "llvm/Analysis/TargetTransformInfo.h" 162f6987baSFedor Sergeev #include "llvm/AsmParser/Parser.h" 172f6987baSFedor Sergeev #include "llvm/IR/Dominators.h" 182f6987baSFedor Sergeev #include "llvm/IR/LLVMContext.h" 192f6987baSFedor Sergeev #include "llvm/Support/SourceMgr.h" 202f6987baSFedor Sergeev #include "gtest/gtest.h" 212f6987baSFedor Sergeev 222f6987baSFedor Sergeev using namespace llvm; 232f6987baSFedor Sergeev 242f6987baSFedor Sergeev static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { 252f6987baSFedor Sergeev SMDiagnostic Err; 262f6987baSFedor Sergeev std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C); 272f6987baSFedor Sergeev if (!Mod) 282f6987baSFedor Sergeev Err.print("LoopRotationUtilsTest", errs()); 292f6987baSFedor Sergeev return Mod; 302f6987baSFedor Sergeev } 312f6987baSFedor Sergeev 322f6987baSFedor Sergeev /// This test contains multi-deopt-exits pattern that might allow loop rotation 332f6987baSFedor Sergeev /// to trigger multiple times if multiple rotations are enabled. 342f6987baSFedor Sergeev /// At least one rotation should be performed, no matter what loop rotation settings are. 352f6987baSFedor Sergeev TEST(LoopRotate, MultiDeoptExit) { 362f6987baSFedor Sergeev LLVMContext C; 372f6987baSFedor Sergeev 382f6987baSFedor Sergeev std::unique_ptr<Module> M = parseIR( 392f6987baSFedor Sergeev C, 402f6987baSFedor Sergeev R"( 412f6987baSFedor Sergeev declare i32 @llvm.experimental.deoptimize.i32(...) 422f6987baSFedor Sergeev 43*7d7c82adSMatt Arsenault define i32 @test(ptr nonnull %a, i64 %x) { 442f6987baSFedor Sergeev entry: 452f6987baSFedor Sergeev br label %for.cond1 462f6987baSFedor Sergeev 472f6987baSFedor Sergeev for.cond1: 482f6987baSFedor Sergeev %idx = phi i64 [ 0, %entry ], [ %idx.next, %for.tail ] 492f6987baSFedor Sergeev %sum = phi i32 [ 0, %entry ], [ %sum.next, %for.tail ] 50*7d7c82adSMatt Arsenault %a.idx = getelementptr inbounds i32, ptr %a, i64 %idx 51*7d7c82adSMatt Arsenault %val.a.idx = load i32, ptr %a.idx, align 4 522f6987baSFedor Sergeev %zero.check = icmp eq i32 %val.a.idx, 0 532f6987baSFedor Sergeev br i1 %zero.check, label %deopt.exit, label %for.cond2 542f6987baSFedor Sergeev 552f6987baSFedor Sergeev for.cond2: 562f6987baSFedor Sergeev %for.check = icmp ult i64 %idx, %x 572f6987baSFedor Sergeev br i1 %for.check, label %for.body, label %return 582f6987baSFedor Sergeev 592f6987baSFedor Sergeev for.body: 602f6987baSFedor Sergeev br label %for.tail 612f6987baSFedor Sergeev 622f6987baSFedor Sergeev for.tail: 632f6987baSFedor Sergeev %sum.next = add i32 %sum, %val.a.idx 642f6987baSFedor Sergeev %idx.next = add nuw nsw i64 %idx, 1 652f6987baSFedor Sergeev br label %for.cond1 662f6987baSFedor Sergeev 672f6987baSFedor Sergeev return: 682f6987baSFedor Sergeev ret i32 %sum 692f6987baSFedor Sergeev 702f6987baSFedor Sergeev deopt.exit: 712f6987baSFedor Sergeev %deopt.val = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %val.a.idx) ] 722f6987baSFedor Sergeev ret i32 %deopt.val 732f6987baSFedor Sergeev })" 742f6987baSFedor Sergeev ); 752f6987baSFedor Sergeev 762f6987baSFedor Sergeev auto *F = M->getFunction("test"); 772f6987baSFedor Sergeev DominatorTree DT(*F); 782f6987baSFedor Sergeev LoopInfo LI(DT); 792f6987baSFedor Sergeev AssumptionCache AC(*F); 802f6987baSFedor Sergeev TargetTransformInfo TTI(M->getDataLayout()); 812f6987baSFedor Sergeev TargetLibraryInfoImpl TLII; 822f6987baSFedor Sergeev TargetLibraryInfo TLI(TLII); 832f6987baSFedor Sergeev ScalarEvolution SE(*F, TLI, AC, DT, LI); 842f6987baSFedor Sergeev SimplifyQuery SQ(M->getDataLayout()); 852f6987baSFedor Sergeev 862f6987baSFedor Sergeev Loop *L = *LI.begin(); 872f6987baSFedor Sergeev 882f6987baSFedor Sergeev bool ret = LoopRotation(L, &LI, &TTI, 892f6987baSFedor Sergeev &AC, &DT, 902f6987baSFedor Sergeev &SE, nullptr, 912f6987baSFedor Sergeev SQ, true, -1, false); 922f6987baSFedor Sergeev EXPECT_TRUE(ret); 932f6987baSFedor Sergeev } 942f6987baSFedor Sergeev 952f6987baSFedor Sergeev /// Checking a special case of multi-deopt exit loop that can not perform 962f6987baSFedor Sergeev /// required amount of rotations due to the desired header containing 972f6987baSFedor Sergeev /// non-duplicatable code. 982f6987baSFedor Sergeev /// Similar to MultiDeoptExit test this one should do at least one rotation and 992f6987baSFedor Sergeev /// pass no matter what loop rotation settings are. 1002f6987baSFedor Sergeev TEST(LoopRotate, MultiDeoptExit_Nondup) { 1012f6987baSFedor Sergeev LLVMContext C; 1022f6987baSFedor Sergeev 1032f6987baSFedor Sergeev std::unique_ptr<Module> M = parseIR( 1042f6987baSFedor Sergeev C, 1052f6987baSFedor Sergeev R"( 1062f6987baSFedor Sergeev ; Rotation should be done once, attempted twice. 1072f6987baSFedor Sergeev ; Second time fails due to non-duplicatable header. 1082f6987baSFedor Sergeev 1092f6987baSFedor Sergeev declare i32 @llvm.experimental.deoptimize.i32(...) 1102f6987baSFedor Sergeev 1112f6987baSFedor Sergeev declare void @nondup() 1122f6987baSFedor Sergeev 113*7d7c82adSMatt Arsenault define i32 @test_nondup(ptr nonnull %a, i64 %x) { 1142f6987baSFedor Sergeev entry: 1152f6987baSFedor Sergeev br label %for.cond1 1162f6987baSFedor Sergeev 1172f6987baSFedor Sergeev for.cond1: 1182f6987baSFedor Sergeev %idx = phi i64 [ 0, %entry ], [ %idx.next, %for.tail ] 1192f6987baSFedor Sergeev %sum = phi i32 [ 0, %entry ], [ %sum.next, %for.tail ] 120*7d7c82adSMatt Arsenault %a.idx = getelementptr inbounds i32, ptr %a, i64 %idx 121*7d7c82adSMatt Arsenault %val.a.idx = load i32, ptr %a.idx, align 4 1222f6987baSFedor Sergeev %zero.check = icmp eq i32 %val.a.idx, 0 1232f6987baSFedor Sergeev br i1 %zero.check, label %deopt.exit, label %for.cond2 1242f6987baSFedor Sergeev 1252f6987baSFedor Sergeev for.cond2: 1262f6987baSFedor Sergeev call void @nondup() noduplicate 1272f6987baSFedor Sergeev %for.check = icmp ult i64 %idx, %x 1282f6987baSFedor Sergeev br i1 %for.check, label %for.body, label %return 1292f6987baSFedor Sergeev 1302f6987baSFedor Sergeev for.body: 1312f6987baSFedor Sergeev br label %for.tail 1322f6987baSFedor Sergeev 1332f6987baSFedor Sergeev for.tail: 1342f6987baSFedor Sergeev %sum.next = add i32 %sum, %val.a.idx 1352f6987baSFedor Sergeev %idx.next = add nuw nsw i64 %idx, 1 1362f6987baSFedor Sergeev br label %for.cond1 1372f6987baSFedor Sergeev 1382f6987baSFedor Sergeev return: 1392f6987baSFedor Sergeev ret i32 %sum 1402f6987baSFedor Sergeev 1412f6987baSFedor Sergeev deopt.exit: 1422f6987baSFedor Sergeev %deopt.val = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %val.a.idx) ] 1432f6987baSFedor Sergeev ret i32 %deopt.val 1442f6987baSFedor Sergeev })" 1452f6987baSFedor Sergeev ); 1462f6987baSFedor Sergeev 1472f6987baSFedor Sergeev auto *F = M->getFunction("test_nondup"); 1482f6987baSFedor Sergeev DominatorTree DT(*F); 1492f6987baSFedor Sergeev LoopInfo LI(DT); 1502f6987baSFedor Sergeev AssumptionCache AC(*F); 1512f6987baSFedor Sergeev TargetTransformInfo TTI(M->getDataLayout()); 1522f6987baSFedor Sergeev TargetLibraryInfoImpl TLII; 1532f6987baSFedor Sergeev TargetLibraryInfo TLI(TLII); 1542f6987baSFedor Sergeev ScalarEvolution SE(*F, TLI, AC, DT, LI); 1552f6987baSFedor Sergeev SimplifyQuery SQ(M->getDataLayout()); 1562f6987baSFedor Sergeev 1572f6987baSFedor Sergeev Loop *L = *LI.begin(); 1582f6987baSFedor Sergeev 1592f6987baSFedor Sergeev bool ret = LoopRotation(L, &LI, &TTI, 1602f6987baSFedor Sergeev &AC, &DT, 1612f6987baSFedor Sergeev &SE, nullptr, 1622f6987baSFedor Sergeev SQ, true, -1, false); 1632f6987baSFedor Sergeev /// LoopRotation should properly report "true" as we still perform the first rotation 1642f6987baSFedor Sergeev /// so we do change the IR. 1652f6987baSFedor Sergeev EXPECT_TRUE(ret); 1662f6987baSFedor Sergeev } 167