19efc761dSJorge Gorbe Moya //===- RegionTest.cpp -----------------------------------------------------===// 29efc761dSJorge Gorbe Moya // 39efc761dSJorge Gorbe Moya // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 49efc761dSJorge Gorbe Moya // See https://llvm.org/LICENSE.txt for license information. 59efc761dSJorge Gorbe Moya // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 69efc761dSJorge Gorbe Moya // 79efc761dSJorge Gorbe Moya //===----------------------------------------------------------------------===// 89efc761dSJorge Gorbe Moya 99efc761dSJorge Gorbe Moya #include "llvm/SandboxIR/Region.h" 10*4b209c5dSvporpo #include "llvm/Analysis/TargetTransformInfo.h" 119efc761dSJorge Gorbe Moya #include "llvm/AsmParser/Parser.h" 122018f4ccSVasileios Porpodas #include "llvm/SandboxIR/Context.h" 13e22b07e7Svporpo #include "llvm/SandboxIR/Function.h" 142018f4ccSVasileios Porpodas #include "llvm/SandboxIR/Instruction.h" 159efc761dSJorge Gorbe Moya #include "llvm/Support/SourceMgr.h" 169efc761dSJorge Gorbe Moya #include "gmock/gmock-matchers.h" 179efc761dSJorge Gorbe Moya #include "gtest/gtest.h" 189efc761dSJorge Gorbe Moya 199efc761dSJorge Gorbe Moya using namespace llvm; 209efc761dSJorge Gorbe Moya 219efc761dSJorge Gorbe Moya struct RegionTest : public testing::Test { 229efc761dSJorge Gorbe Moya LLVMContext C; 239efc761dSJorge Gorbe Moya std::unique_ptr<Module> M; 24*4b209c5dSvporpo std::unique_ptr<TargetTransformInfo> TTI; 259efc761dSJorge Gorbe Moya 269efc761dSJorge Gorbe Moya void parseIR(LLVMContext &C, const char *IR) { 279efc761dSJorge Gorbe Moya SMDiagnostic Err; 289efc761dSJorge Gorbe Moya M = parseAssemblyString(IR, Err, C); 29*4b209c5dSvporpo TTI = std::make_unique<TargetTransformInfo>(M->getDataLayout()); 309efc761dSJorge Gorbe Moya if (!M) 319efc761dSJorge Gorbe Moya Err.print("RegionTest", errs()); 329efc761dSJorge Gorbe Moya } 339efc761dSJorge Gorbe Moya }; 349efc761dSJorge Gorbe Moya 359efc761dSJorge Gorbe Moya TEST_F(RegionTest, Basic) { 369efc761dSJorge Gorbe Moya parseIR(C, R"IR( 379efc761dSJorge Gorbe Moya define i8 @foo(i8 %v0, i8 %v1) { 389efc761dSJorge Gorbe Moya %t0 = add i8 %v0, 1 399efc761dSJorge Gorbe Moya %t1 = add i8 %t0, %v1 409efc761dSJorge Gorbe Moya ret i8 %t1 419efc761dSJorge Gorbe Moya } 429efc761dSJorge Gorbe Moya )IR"); 439efc761dSJorge Gorbe Moya llvm::Function *LLVMF = &*M->getFunction("foo"); 449efc761dSJorge Gorbe Moya sandboxir::Context Ctx(C); 459efc761dSJorge Gorbe Moya auto *F = Ctx.createFunction(LLVMF); 469efc761dSJorge Gorbe Moya auto *BB = &*F->begin(); 479efc761dSJorge Gorbe Moya auto It = BB->begin(); 489efc761dSJorge Gorbe Moya auto *T0 = cast<sandboxir::Instruction>(&*It++); 499efc761dSJorge Gorbe Moya auto *T1 = cast<sandboxir::Instruction>(&*It++); 509efc761dSJorge Gorbe Moya auto *Ret = cast<sandboxir::Instruction>(&*It++); 51*4b209c5dSvporpo sandboxir::Region Rgn(Ctx, *TTI); 529efc761dSJorge Gorbe Moya 539efc761dSJorge Gorbe Moya // Check getContext. 549efc761dSJorge Gorbe Moya EXPECT_EQ(&Ctx, &Rgn.getContext()); 559efc761dSJorge Gorbe Moya 569efc761dSJorge Gorbe Moya // Check add / remove / empty. 579efc761dSJorge Gorbe Moya EXPECT_TRUE(Rgn.empty()); 589efc761dSJorge Gorbe Moya Rgn.add(T0); 599efc761dSJorge Gorbe Moya EXPECT_FALSE(Rgn.empty()); 609efc761dSJorge Gorbe Moya Rgn.remove(T0); 619efc761dSJorge Gorbe Moya EXPECT_TRUE(Rgn.empty()); 629efc761dSJorge Gorbe Moya 639efc761dSJorge Gorbe Moya // Check iteration. 649efc761dSJorge Gorbe Moya Rgn.add(T0); 659efc761dSJorge Gorbe Moya Rgn.add(T1); 669efc761dSJorge Gorbe Moya Rgn.add(Ret); 679efc761dSJorge Gorbe Moya // Use an ordered matcher because we're supposed to preserve the insertion 689efc761dSJorge Gorbe Moya // order for determinism. 699efc761dSJorge Gorbe Moya EXPECT_THAT(Rgn.insts(), testing::ElementsAre(T0, T1, Ret)); 709efc761dSJorge Gorbe Moya 719efc761dSJorge Gorbe Moya // Check contains 729efc761dSJorge Gorbe Moya EXPECT_TRUE(Rgn.contains(T0)); 739efc761dSJorge Gorbe Moya Rgn.remove(T0); 749efc761dSJorge Gorbe Moya EXPECT_FALSE(Rgn.contains(T0)); 759efc761dSJorge Gorbe Moya 769efc761dSJorge Gorbe Moya #ifndef NDEBUG 779efc761dSJorge Gorbe Moya // Check equality comparison. Insert in reverse order into `Other` to check 789efc761dSJorge Gorbe Moya // that comparison is order-independent. 79*4b209c5dSvporpo sandboxir::Region Other(Ctx, *TTI); 809efc761dSJorge Gorbe Moya Other.add(Ret); 819efc761dSJorge Gorbe Moya EXPECT_NE(Rgn, Other); 829efc761dSJorge Gorbe Moya Other.add(T1); 839efc761dSJorge Gorbe Moya EXPECT_EQ(Rgn, Other); 849efc761dSJorge Gorbe Moya #endif 859efc761dSJorge Gorbe Moya } 869efc761dSJorge Gorbe Moya 87b22c3c1eSJorge Gorbe Moya TEST_F(RegionTest, CallbackUpdates) { 88b22c3c1eSJorge Gorbe Moya parseIR(C, R"IR( 89b22c3c1eSJorge Gorbe Moya define i8 @foo(i8 %v0, i8 %v1, ptr %ptr) { 90b22c3c1eSJorge Gorbe Moya %t0 = add i8 %v0, 1 91b22c3c1eSJorge Gorbe Moya %t1 = add i8 %t0, %v1 92b22c3c1eSJorge Gorbe Moya ret i8 %t0 93b22c3c1eSJorge Gorbe Moya } 94b22c3c1eSJorge Gorbe Moya )IR"); 95b22c3c1eSJorge Gorbe Moya llvm::Function *LLVMF = &*M->getFunction("foo"); 96b22c3c1eSJorge Gorbe Moya sandboxir::Context Ctx(C); 97b22c3c1eSJorge Gorbe Moya auto *F = Ctx.createFunction(LLVMF); 98b22c3c1eSJorge Gorbe Moya auto *Ptr = F->getArg(2); 99b22c3c1eSJorge Gorbe Moya auto *BB = &*F->begin(); 100b22c3c1eSJorge Gorbe Moya auto It = BB->begin(); 101b22c3c1eSJorge Gorbe Moya auto *T0 = cast<sandboxir::Instruction>(&*It++); 102b22c3c1eSJorge Gorbe Moya auto *T1 = cast<sandboxir::Instruction>(&*It++); 103b22c3c1eSJorge Gorbe Moya auto *Ret = cast<sandboxir::Instruction>(&*It++); 104*4b209c5dSvporpo sandboxir::Region Rgn(Ctx, *TTI); 105b22c3c1eSJorge Gorbe Moya Rgn.add(T0); 106b22c3c1eSJorge Gorbe Moya Rgn.add(T1); 107b22c3c1eSJorge Gorbe Moya 108b22c3c1eSJorge Gorbe Moya // Test creation. 109b22c3c1eSJorge Gorbe Moya auto *NewI = sandboxir::StoreInst::create(T0, Ptr, /*Align=*/std::nullopt, 110b22c3c1eSJorge Gorbe Moya Ret->getIterator(), Ctx); 111b22c3c1eSJorge Gorbe Moya EXPECT_THAT(Rgn.insts(), testing::ElementsAre(T0, T1, NewI)); 112b22c3c1eSJorge Gorbe Moya 113b22c3c1eSJorge Gorbe Moya // Test deletion. 114b22c3c1eSJorge Gorbe Moya T1->eraseFromParent(); 115b22c3c1eSJorge Gorbe Moya EXPECT_THAT(Rgn.insts(), testing::ElementsAre(T0, NewI)); 116b22c3c1eSJorge Gorbe Moya } 117b22c3c1eSJorge Gorbe Moya 1189efc761dSJorge Gorbe Moya TEST_F(RegionTest, MetadataFromIR) { 1199efc761dSJorge Gorbe Moya parseIR(C, R"IR( 1209efc761dSJorge Gorbe Moya define i8 @foo(i8 %v0, i8 %v1) { 1219efc761dSJorge Gorbe Moya %t0 = add i8 %v0, 1, !sandboxvec !0 1229efc761dSJorge Gorbe Moya %t1 = add i8 %t0, %v1, !sandboxvec !1 1239efc761dSJorge Gorbe Moya %t2 = add i8 %t1, %v1, !sandboxvec !1 1249efc761dSJorge Gorbe Moya ret i8 %t2 1259efc761dSJorge Gorbe Moya } 1269efc761dSJorge Gorbe Moya 1279efc761dSJorge Gorbe Moya !0 = distinct !{!"sandboxregion"} 1289efc761dSJorge Gorbe Moya !1 = distinct !{!"sandboxregion"} 1299efc761dSJorge Gorbe Moya )IR"); 1309efc761dSJorge Gorbe Moya llvm::Function *LLVMF = &*M->getFunction("foo"); 1319efc761dSJorge Gorbe Moya sandboxir::Context Ctx(C); 1329efc761dSJorge Gorbe Moya auto *F = Ctx.createFunction(LLVMF); 1339efc761dSJorge Gorbe Moya auto *BB = &*F->begin(); 1349efc761dSJorge Gorbe Moya auto It = BB->begin(); 1359efc761dSJorge Gorbe Moya auto *T0 = cast<sandboxir::Instruction>(&*It++); 1369efc761dSJorge Gorbe Moya auto *T1 = cast<sandboxir::Instruction>(&*It++); 1379efc761dSJorge Gorbe Moya auto *T2 = cast<sandboxir::Instruction>(&*It++); 1389efc761dSJorge Gorbe Moya 1399efc761dSJorge Gorbe Moya SmallVector<std::unique_ptr<sandboxir::Region>> Regions = 140*4b209c5dSvporpo sandboxir::Region::createRegionsFromMD(*F, *TTI); 1419efc761dSJorge Gorbe Moya EXPECT_THAT(Regions[0]->insts(), testing::UnorderedElementsAre(T0)); 1429efc761dSJorge Gorbe Moya EXPECT_THAT(Regions[1]->insts(), testing::UnorderedElementsAre(T1, T2)); 1439efc761dSJorge Gorbe Moya } 1449efc761dSJorge Gorbe Moya 1452aa1dbf9SJorge Gorbe Moya TEST_F(RegionTest, NonContiguousRegion) { 1462aa1dbf9SJorge Gorbe Moya parseIR(C, R"IR( 1472aa1dbf9SJorge Gorbe Moya define i8 @foo(i8 %v0, i8 %v1) { 1482aa1dbf9SJorge Gorbe Moya %t0 = add i8 %v0, 1, !sandboxvec !0 1492aa1dbf9SJorge Gorbe Moya %t1 = add i8 %t0, %v1 1502aa1dbf9SJorge Gorbe Moya %t2 = add i8 %t1, %v1, !sandboxvec !0 1512aa1dbf9SJorge Gorbe Moya ret i8 %t2 1522aa1dbf9SJorge Gorbe Moya } 1532aa1dbf9SJorge Gorbe Moya 1542aa1dbf9SJorge Gorbe Moya !0 = distinct !{!"sandboxregion"} 1552aa1dbf9SJorge Gorbe Moya )IR"); 1562aa1dbf9SJorge Gorbe Moya llvm::Function *LLVMF = &*M->getFunction("foo"); 1572aa1dbf9SJorge Gorbe Moya sandboxir::Context Ctx(C); 1582aa1dbf9SJorge Gorbe Moya auto *F = Ctx.createFunction(LLVMF); 1592aa1dbf9SJorge Gorbe Moya auto *BB = &*F->begin(); 1602aa1dbf9SJorge Gorbe Moya auto It = BB->begin(); 1612aa1dbf9SJorge Gorbe Moya auto *T0 = cast<sandboxir::Instruction>(&*It++); 1622aa1dbf9SJorge Gorbe Moya [[maybe_unused]] auto *T1 = cast<sandboxir::Instruction>(&*It++); 1632aa1dbf9SJorge Gorbe Moya auto *T2 = cast<sandboxir::Instruction>(&*It++); 1642aa1dbf9SJorge Gorbe Moya 1652aa1dbf9SJorge Gorbe Moya SmallVector<std::unique_ptr<sandboxir::Region>> Regions = 166*4b209c5dSvporpo sandboxir::Region::createRegionsFromMD(*F, *TTI); 1672aa1dbf9SJorge Gorbe Moya EXPECT_THAT(Regions[0]->insts(), testing::UnorderedElementsAre(T0, T2)); 1682aa1dbf9SJorge Gorbe Moya } 1692aa1dbf9SJorge Gorbe Moya 1709efc761dSJorge Gorbe Moya TEST_F(RegionTest, DumpedMetadata) { 1719efc761dSJorge Gorbe Moya parseIR(C, R"IR( 1729efc761dSJorge Gorbe Moya define i8 @foo(i8 %v0, i8 %v1) { 1739efc761dSJorge Gorbe Moya %t0 = add i8 %v0, 1 1749efc761dSJorge Gorbe Moya %t1 = add i8 %t0, %v1 1759efc761dSJorge Gorbe Moya %t2 = add i8 %t1, %v1 1769efc761dSJorge Gorbe Moya ret i8 %t1 1779efc761dSJorge Gorbe Moya } 1789efc761dSJorge Gorbe Moya )IR"); 1799efc761dSJorge Gorbe Moya llvm::Function *LLVMF = &*M->getFunction("foo"); 1809efc761dSJorge Gorbe Moya sandboxir::Context Ctx(C); 1819efc761dSJorge Gorbe Moya auto *F = Ctx.createFunction(LLVMF); 1829efc761dSJorge Gorbe Moya auto *BB = &*F->begin(); 1839efc761dSJorge Gorbe Moya auto It = BB->begin(); 1849efc761dSJorge Gorbe Moya auto *T0 = cast<sandboxir::Instruction>(&*It++); 1859efc761dSJorge Gorbe Moya [[maybe_unused]] auto *T1 = cast<sandboxir::Instruction>(&*It++); 1869efc761dSJorge Gorbe Moya auto *T2 = cast<sandboxir::Instruction>(&*It++); 1879efc761dSJorge Gorbe Moya [[maybe_unused]] auto *Ret = cast<sandboxir::Instruction>(&*It++); 188*4b209c5dSvporpo sandboxir::Region Rgn(Ctx, *TTI); 1899efc761dSJorge Gorbe Moya Rgn.add(T0); 190*4b209c5dSvporpo sandboxir::Region Rgn2(Ctx, *TTI); 1919efc761dSJorge Gorbe Moya Rgn2.add(T2); 1929efc761dSJorge Gorbe Moya 1939efc761dSJorge Gorbe Moya std::string output; 1949efc761dSJorge Gorbe Moya llvm::raw_string_ostream RSO(output); 1959efc761dSJorge Gorbe Moya M->print(RSO, nullptr, /*ShouldPreserveUseListOrder=*/true, 1969efc761dSJorge Gorbe Moya /*IsForDebug=*/true); 1979efc761dSJorge Gorbe Moya 1989efc761dSJorge Gorbe Moya // TODO: Replace this with a lit test, which is more suitable for this kind 1999efc761dSJorge Gorbe Moya // of IR comparison. 2009efc761dSJorge Gorbe Moya std::string expected = R"(; ModuleID = '<string>' 2019efc761dSJorge Gorbe Moya source_filename = "<string>" 2029efc761dSJorge Gorbe Moya 2039efc761dSJorge Gorbe Moya define i8 @foo(i8 %v0, i8 %v1) { 2049efc761dSJorge Gorbe Moya %t0 = add i8 %v0, 1, !sandboxvec !0 2059efc761dSJorge Gorbe Moya %t1 = add i8 %t0, %v1 2069efc761dSJorge Gorbe Moya %t2 = add i8 %t1, %v1, !sandboxvec !1 2079efc761dSJorge Gorbe Moya ret i8 %t1 2089efc761dSJorge Gorbe Moya } 2099efc761dSJorge Gorbe Moya 2109efc761dSJorge Gorbe Moya !0 = distinct !{!"sandboxregion"} 2119efc761dSJorge Gorbe Moya !1 = distinct !{!"sandboxregion"} 2129efc761dSJorge Gorbe Moya )"; 2139efc761dSJorge Gorbe Moya EXPECT_EQ(expected, output); 2149efc761dSJorge Gorbe Moya } 2159efc761dSJorge Gorbe Moya 2169efc761dSJorge Gorbe Moya TEST_F(RegionTest, MetadataRoundTrip) { 2179efc761dSJorge Gorbe Moya parseIR(C, R"IR( 2189efc761dSJorge Gorbe Moya define i8 @foo(i8 %v0, i8 %v1) { 2199efc761dSJorge Gorbe Moya %t0 = add i8 %v0, 1 2209efc761dSJorge Gorbe Moya %t1 = add i8 %t0, %v1 2219efc761dSJorge Gorbe Moya ret i8 %t1 2229efc761dSJorge Gorbe Moya } 2239efc761dSJorge Gorbe Moya )IR"); 2249efc761dSJorge Gorbe Moya llvm::Function *LLVMF = &*M->getFunction("foo"); 2259efc761dSJorge Gorbe Moya sandboxir::Context Ctx(C); 2269efc761dSJorge Gorbe Moya auto *F = Ctx.createFunction(LLVMF); 2279efc761dSJorge Gorbe Moya auto *BB = &*F->begin(); 2289efc761dSJorge Gorbe Moya auto It = BB->begin(); 2299efc761dSJorge Gorbe Moya auto *T0 = cast<sandboxir::Instruction>(&*It++); 2309efc761dSJorge Gorbe Moya auto *T1 = cast<sandboxir::Instruction>(&*It++); 2319efc761dSJorge Gorbe Moya 232*4b209c5dSvporpo sandboxir::Region Rgn(Ctx, *TTI); 2339efc761dSJorge Gorbe Moya Rgn.add(T0); 2349efc761dSJorge Gorbe Moya Rgn.add(T1); 2359efc761dSJorge Gorbe Moya 2369efc761dSJorge Gorbe Moya SmallVector<std::unique_ptr<sandboxir::Region>> Regions = 237*4b209c5dSvporpo sandboxir::Region::createRegionsFromMD(*F, *TTI); 2389efc761dSJorge Gorbe Moya ASSERT_EQ(1U, Regions.size()); 2399efc761dSJorge Gorbe Moya #ifndef NDEBUG 2409efc761dSJorge Gorbe Moya EXPECT_EQ(Rgn, *Regions[0].get()); 2419efc761dSJorge Gorbe Moya #endif 2429efc761dSJorge Gorbe Moya } 243*4b209c5dSvporpo 244*4b209c5dSvporpo TEST_F(RegionTest, RegionCost) { 245*4b209c5dSvporpo parseIR(C, R"IR( 246*4b209c5dSvporpo define void @foo(i8 %v0, i8 %v1, i8 %v2) { 247*4b209c5dSvporpo %add0 = add i8 %v0, 1 248*4b209c5dSvporpo %add1 = add i8 %v1, 2 249*4b209c5dSvporpo %add2 = add i8 %v2, 3 250*4b209c5dSvporpo ret void 251*4b209c5dSvporpo } 252*4b209c5dSvporpo )IR"); 253*4b209c5dSvporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 254*4b209c5dSvporpo auto *LLVMBB = &*LLVMF->begin(); 255*4b209c5dSvporpo auto LLVMIt = LLVMBB->begin(); 256*4b209c5dSvporpo auto *LLVMAdd0 = &*LLVMIt++; 257*4b209c5dSvporpo auto *LLVMAdd1 = &*LLVMIt++; 258*4b209c5dSvporpo auto *LLVMAdd2 = &*LLVMIt++; 259*4b209c5dSvporpo 260*4b209c5dSvporpo sandboxir::Context Ctx(C); 261*4b209c5dSvporpo auto *F = Ctx.createFunction(LLVMF); 262*4b209c5dSvporpo auto *BB = &*F->begin(); 263*4b209c5dSvporpo auto It = BB->begin(); 264*4b209c5dSvporpo auto *Add0 = cast<sandboxir::Instruction>(&*It++); 265*4b209c5dSvporpo auto *Add1 = cast<sandboxir::Instruction>(&*It++); 266*4b209c5dSvporpo auto *Add2 = cast<sandboxir::Instruction>(&*It++); 267*4b209c5dSvporpo 268*4b209c5dSvporpo sandboxir::Region Rgn(Ctx, *TTI); 269*4b209c5dSvporpo const auto &SB = Rgn.getScoreboard(); 270*4b209c5dSvporpo EXPECT_EQ(SB.getAfterCost(), 0); 271*4b209c5dSvporpo EXPECT_EQ(SB.getBeforeCost(), 0); 272*4b209c5dSvporpo 273*4b209c5dSvporpo auto GetCost = [this](llvm::Instruction *LLVMI) { 274*4b209c5dSvporpo constexpr static TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput; 275*4b209c5dSvporpo SmallVector<const llvm::Value *> Operands(LLVMI->operands()); 276*4b209c5dSvporpo return TTI->getInstructionCost(LLVMI, Operands, CostKind); 277*4b209c5dSvporpo }; 278*4b209c5dSvporpo // Add `Add0` to the region, should be counted in "After". 279*4b209c5dSvporpo Rgn.add(Add0); 280*4b209c5dSvporpo EXPECT_EQ(SB.getBeforeCost(), 0); 281*4b209c5dSvporpo EXPECT_EQ(SB.getAfterCost(), GetCost(LLVMAdd0)); 282*4b209c5dSvporpo // Same for `Add1`. 283*4b209c5dSvporpo Rgn.add(Add1); 284*4b209c5dSvporpo EXPECT_EQ(SB.getBeforeCost(), 0); 285*4b209c5dSvporpo EXPECT_EQ(SB.getAfterCost(), GetCost(LLVMAdd0) + GetCost(LLVMAdd1)); 286*4b209c5dSvporpo // Remove `Add0`, should be subtracted from "After". 287*4b209c5dSvporpo Rgn.remove(Add0); 288*4b209c5dSvporpo EXPECT_EQ(SB.getBeforeCost(), 0); 289*4b209c5dSvporpo EXPECT_EQ(SB.getAfterCost(), GetCost(LLVMAdd1)); 290*4b209c5dSvporpo // Remove `Add2` which was never in the region, should counted in "Before". 291*4b209c5dSvporpo Rgn.remove(Add2); 292*4b209c5dSvporpo EXPECT_EQ(SB.getBeforeCost(), GetCost(LLVMAdd2)); 293*4b209c5dSvporpo EXPECT_EQ(SB.getAfterCost(), GetCost(LLVMAdd1)); 294*4b209c5dSvporpo } 295