brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.8 KiB · 5d7283f Raw
513 lines · cpp
1//===- RegionTest.cpp -----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/SandboxIR/Region.h"10#include "llvm/Analysis/TargetTransformInfo.h"11#include "llvm/AsmParser/Parser.h"12#include "llvm/SandboxIR/Context.h"13#include "llvm/SandboxIR/Function.h"14#include "llvm/SandboxIR/Instruction.h"15#include "llvm/Support/SourceMgr.h"16#include "gmock/gmock-matchers.h"17#include "gtest/gtest.h"18 19using namespace llvm;20 21struct RegionTest : public testing::Test {22  LLVMContext C;23  std::unique_ptr<Module> M;24  std::unique_ptr<TargetTransformInfo> TTI;25 26  void parseIR(LLVMContext &C, const char *IR) {27    SMDiagnostic Err;28    M = parseAssemblyString(IR, Err, C);29    TTI = std::make_unique<TargetTransformInfo>(M->getDataLayout());30    if (!M)31      Err.print("RegionTest", errs());32  }33};34 35TEST_F(RegionTest, Basic) {36  parseIR(C, R"IR(37define i8 @foo(i8 %v0, i8 %v1) {38  %t0 = add i8 %v0, 139  %t1 = add i8 %t0, %v140  ret i8 %t141}42)IR");43  llvm::Function *LLVMF = &*M->getFunction("foo");44  sandboxir::Context Ctx(C);45  auto *F = Ctx.createFunction(LLVMF);46  auto *BB = &*F->begin();47  auto It = BB->begin();48  auto *T0 = cast<sandboxir::Instruction>(&*It++);49  auto *T1 = cast<sandboxir::Instruction>(&*It++);50  auto *Ret = cast<sandboxir::Instruction>(&*It++);51  sandboxir::Region Rgn(Ctx, *TTI);52 53  // Check getContext.54  EXPECT_EQ(&Ctx, &Rgn.getContext());55 56  // Check add / remove / empty.57  EXPECT_TRUE(Rgn.empty());58  sandboxir::RegionInternalsAttorney::add(Rgn, T0);59  EXPECT_FALSE(Rgn.empty());60  sandboxir::RegionInternalsAttorney::remove(Rgn, T0);61  EXPECT_TRUE(Rgn.empty());62 63  // Check iteration.64  sandboxir::RegionInternalsAttorney::add(Rgn, T0);65  sandboxir::RegionInternalsAttorney::add(Rgn, T1);66  sandboxir::RegionInternalsAttorney::add(Rgn, Ret);67  // Use an ordered matcher because we're supposed to preserve the insertion68  // order for determinism.69  EXPECT_THAT(Rgn.insts(), testing::ElementsAre(T0, T1, Ret));70 71  // Check contains72  EXPECT_TRUE(Rgn.contains(T0));73  sandboxir::RegionInternalsAttorney::remove(Rgn, T0);74  EXPECT_FALSE(Rgn.contains(T0));75 76#ifndef NDEBUG77  // Check equality comparison. Insert in reverse order into `Other` to check78  // that comparison is order-independent.79  sandboxir::Region Other(Ctx, *TTI);80  sandboxir::RegionInternalsAttorney::add(Other, Ret);81  EXPECT_NE(Rgn, Other);82  sandboxir::RegionInternalsAttorney::add(Other, T1);83  EXPECT_EQ(Rgn, Other);84#endif85}86 87TEST_F(RegionTest, CallbackUpdates) {88  parseIR(C, R"IR(89define i8 @foo(i8 %v0, i8 %v1, ptr %ptr) {90  %t0 = add i8 %v0, 191  %t1 = add i8 %t0, %v192  ret i8 %t093}94)IR");95  llvm::Function *LLVMF = &*M->getFunction("foo");96  sandboxir::Context Ctx(C);97  auto *F = Ctx.createFunction(LLVMF);98  auto *Ptr = F->getArg(2);99  auto *BB = &*F->begin();100  auto It = BB->begin();101  auto *T0 = cast<sandboxir::Instruction>(&*It++);102  auto *T1 = cast<sandboxir::Instruction>(&*It++);103  auto *Ret = cast<sandboxir::Instruction>(&*It++);104  sandboxir::Region Rgn(Ctx, *TTI);105  sandboxir::RegionInternalsAttorney::add(Rgn, T0);106  sandboxir::RegionInternalsAttorney::add(Rgn, T1);107 108  // Test creation.109  auto *NewI = sandboxir::StoreInst::create(T0, Ptr, /*Align=*/std::nullopt,110                                            Ret->getIterator(), Ctx);111  EXPECT_THAT(Rgn.insts(), testing::ElementsAre(T0, T1, NewI));112 113  // Test deletion.114  T1->eraseFromParent();115  EXPECT_THAT(Rgn.insts(), testing::ElementsAre(T0, NewI));116}117 118TEST_F(RegionTest, MetadataFromIR) {119  parseIR(C, R"IR(120define i8 @foo(i8 %v0, i8 %v1) {121  %t0 = add i8 %v0, 1, !sandboxvec !0122  %t1 = add i8 %t0, %v1, !sandboxvec !1123  %t2 = add i8 %t1, %v1, !sandboxvec !1124  ret i8 %t2125}126 127!0 = distinct !{!"sandboxregion"}128!1 = distinct !{!"sandboxregion"}129)IR");130  llvm::Function *LLVMF = &*M->getFunction("foo");131  sandboxir::Context Ctx(C);132  auto *F = Ctx.createFunction(LLVMF);133  auto *BB = &*F->begin();134  auto It = BB->begin();135  auto *T0 = cast<sandboxir::Instruction>(&*It++);136  auto *T1 = cast<sandboxir::Instruction>(&*It++);137  auto *T2 = cast<sandboxir::Instruction>(&*It++);138 139  SmallVector<std::unique_ptr<sandboxir::Region>> Regions =140      sandboxir::Region::createRegionsFromMD(*F, *TTI);141  EXPECT_THAT(Regions[0]->insts(), testing::UnorderedElementsAre(T0));142  EXPECT_THAT(Regions[1]->insts(), testing::UnorderedElementsAre(T1, T2));143}144 145TEST_F(RegionTest, NonContiguousRegion) {146  parseIR(C, R"IR(147define i8 @foo(i8 %v0, i8 %v1) {148  %t0 = add i8 %v0, 1, !sandboxvec !0149  %t1 = add i8 %t0, %v1150  %t2 = add i8 %t1, %v1, !sandboxvec !0151  ret i8 %t2152}153 154!0 = distinct !{!"sandboxregion"}155)IR");156  llvm::Function *LLVMF = &*M->getFunction("foo");157  sandboxir::Context Ctx(C);158  auto *F = Ctx.createFunction(LLVMF);159  auto *BB = &*F->begin();160  auto It = BB->begin();161  auto *T0 = cast<sandboxir::Instruction>(&*It++);162  [[maybe_unused]] auto *T1 = cast<sandboxir::Instruction>(&*It++);163  auto *T2 = cast<sandboxir::Instruction>(&*It++);164 165  SmallVector<std::unique_ptr<sandboxir::Region>> Regions =166      sandboxir::Region::createRegionsFromMD(*F, *TTI);167  EXPECT_THAT(Regions[0]->insts(), testing::UnorderedElementsAre(T0, T2));168}169 170TEST_F(RegionTest, DumpedMetadata) {171  parseIR(C, R"IR(172define i8 @foo(i8 %v0, i8 %v1) {173  %t0 = add i8 %v0, 1174  %t1 = add i8 %t0, %v1175  %t2 = add i8 %t1, %v1176  ret i8 %t1177}178)IR");179  llvm::Function *LLVMF = &*M->getFunction("foo");180  sandboxir::Context Ctx(C);181  auto *F = Ctx.createFunction(LLVMF);182  auto *BB = &*F->begin();183  auto It = BB->begin();184  auto *T0 = cast<sandboxir::Instruction>(&*It++);185  [[maybe_unused]] auto *T1 = cast<sandboxir::Instruction>(&*It++);186  auto *T2 = cast<sandboxir::Instruction>(&*It++);187  [[maybe_unused]] auto *Ret = cast<sandboxir::Instruction>(&*It++);188  sandboxir::Region Rgn(Ctx, *TTI);189  sandboxir::RegionInternalsAttorney::add(Rgn, T0);190  sandboxir::Region Rgn2(Ctx, *TTI);191  sandboxir::RegionInternalsAttorney::add(Rgn2, T2);192 193  std::string output;194  llvm::raw_string_ostream RSO(output);195  M->print(RSO, nullptr, /*ShouldPreserveUseListOrder=*/true,196           /*IsForDebug=*/true);197 198  // TODO: Replace this with a lit test, which is more suitable for this kind199  // of IR comparison.200  std::string expected = R"(; ModuleID = '<string>'201source_filename = "<string>"202 203define i8 @foo(i8 %v0, i8 %v1) {204  %t0 = add i8 %v0, 1, !sandboxvec !0205  %t1 = add i8 %t0, %v1206  %t2 = add i8 %t1, %v1, !sandboxvec !1207  ret i8 %t1208}209 210!0 = distinct !{!"sandboxregion"}211!1 = distinct !{!"sandboxregion"}212)";213  EXPECT_EQ(expected, output);214}215 216TEST_F(RegionTest, MetadataRoundTrip) {217  parseIR(C, R"IR(218define i8 @foo(i8 %v0, i8 %v1) {219  %t0 = add i8 %v0, 1220  %t1 = add i8 %t0, %v1221  ret i8 %t1222}223)IR");224  llvm::Function *LLVMF = &*M->getFunction("foo");225  sandboxir::Context Ctx(C);226  auto *F = Ctx.createFunction(LLVMF);227  auto *BB = &*F->begin();228  auto It = BB->begin();229  auto *T0 = cast<sandboxir::Instruction>(&*It++);230  auto *T1 = cast<sandboxir::Instruction>(&*It++);231 232  sandboxir::Region Rgn(Ctx, *TTI);233  sandboxir::RegionInternalsAttorney::add(Rgn, T0);234  sandboxir::RegionInternalsAttorney::add(Rgn, T1);235 236  SmallVector<std::unique_ptr<sandboxir::Region>> Regions =237      sandboxir::Region::createRegionsFromMD(*F, *TTI);238  ASSERT_EQ(1U, Regions.size());239#ifndef NDEBUG240  EXPECT_EQ(Rgn, *Regions[0].get());241#endif242}243 244TEST_F(RegionTest, RegionCost) {245  parseIR(C, R"IR(246define void @foo(i8 %v0, i8 %v1, i8 %v2) {247  %add0 = add i8 %v0, 1248  %add1 = add i8 %v1, 2249  %add2 = add i8 %v2, 3250  ret void251}252)IR");253  llvm::Function *LLVMF = &*M->getFunction("foo");254  auto *LLVMBB = &*LLVMF->begin();255  auto LLVMIt = LLVMBB->begin();256  auto *LLVMAdd0 = &*LLVMIt++;257  auto *LLVMAdd1 = &*LLVMIt++;258  auto *LLVMAdd2 = &*LLVMIt++;259 260  sandboxir::Context Ctx(C);261  auto *F = Ctx.createFunction(LLVMF);262  auto *BB = &*F->begin();263  auto It = BB->begin();264  auto *Add0 = cast<sandboxir::Instruction>(&*It++);265  auto *Add1 = cast<sandboxir::Instruction>(&*It++);266  auto *Add2 = cast<sandboxir::Instruction>(&*It++);267 268  sandboxir::Region Rgn(Ctx, *TTI);269  const auto &SB = Rgn.getScoreboard();270  EXPECT_EQ(SB.getAfterCost(), 0);271  EXPECT_EQ(SB.getBeforeCost(), 0);272 273  auto GetCost = [this](llvm::Instruction *LLVMI) {274    constexpr static TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput;275    SmallVector<const llvm::Value *> Operands(LLVMI->operands());276    return TTI->getInstructionCost(LLVMI, Operands, CostKind);277  };278  // Add `Add0` to the region, should be counted in "After".279  sandboxir::RegionInternalsAttorney::add(Rgn, Add0);280  EXPECT_EQ(SB.getBeforeCost(), 0);281  EXPECT_EQ(SB.getAfterCost(), GetCost(LLVMAdd0));282  // Same for `Add1`.283  sandboxir::RegionInternalsAttorney::add(Rgn, Add1);284  EXPECT_EQ(SB.getBeforeCost(), 0);285  EXPECT_EQ(SB.getAfterCost(), GetCost(LLVMAdd0) + GetCost(LLVMAdd1));286  // Remove `Add0`, should be subtracted from "After".287  sandboxir::RegionInternalsAttorney::remove(Rgn, Add0);288  EXPECT_EQ(SB.getBeforeCost(), 0);289  EXPECT_EQ(SB.getAfterCost(), GetCost(LLVMAdd1));290  // Remove `Add2` which was never in the region, should counted in "Before".291  sandboxir::RegionInternalsAttorney::remove(Rgn, Add2);292  EXPECT_EQ(SB.getBeforeCost(), GetCost(LLVMAdd2));293  EXPECT_EQ(SB.getAfterCost(), GetCost(LLVMAdd1));294}295 296TEST_F(RegionTest, Aux) {297  parseIR(C, R"IR(298define void @foo(i8 %v) {299  %t0 = add i8 %v, 0, !sandboxvec !0, !sandboxaux !2300  %t1 = add i8 %v, 1, !sandboxvec !0, !sandboxaux !3301  %t2 = add i8 %v, 2, !sandboxvec !1302  %t3 = add i8 %v, 3, !sandboxvec !1, !sandboxaux !2303  %t4 = add i8 %v, 4, !sandboxvec !1, !sandboxaux !4304  %t5 = add i8 %v, 5, !sandboxvec !1, !sandboxaux !3305  ret void306}307 308!0 = distinct !{!"sandboxregion"}309!1 = distinct !{!"sandboxregion"}310 311!2 = !{i32 0}312!3 = !{i32 1}313!4 = !{i32 2}314)IR");315  llvm::Function *LLVMF = &*M->getFunction("foo");316  auto *LLVMBB = &*LLVMF->begin();317  auto LLVMIt = LLVMBB->begin();318  auto *LLVMI0 = &*LLVMIt++;319  auto *LLVMI1 = &*LLVMIt++;320  sandboxir::Context Ctx(C);321  auto *F = Ctx.createFunction(LLVMF);322  auto *BB = &*F->begin();323  auto It = BB->begin();324  auto *T0 = cast<sandboxir::Instruction>(&*It++);325  auto *T1 = cast<sandboxir::Instruction>(&*It++);326  auto *T2 = cast<sandboxir::Instruction>(&*It++);327  auto *T3 = cast<sandboxir::Instruction>(&*It++);328  auto *T4 = cast<sandboxir::Instruction>(&*It++);329  auto *T5 = cast<sandboxir::Instruction>(&*It++);330 331  SmallVector<std::unique_ptr<sandboxir::Region>> Regions =332      sandboxir::Region::createRegionsFromMD(*F, *TTI);333  // Check that the regions are correct.334  EXPECT_THAT(Regions[0]->insts(), testing::UnorderedElementsAre(T0, T1));335  EXPECT_THAT(Regions[1]->insts(),336              testing::UnorderedElementsAre(T2, T3, T4, T5));337  // Check aux.338  EXPECT_THAT(Regions[0]->getAux(), testing::ElementsAre(T0, T1));339  EXPECT_THAT(Regions[1]->getAux(), testing::ElementsAre(T3, T5, T4));340  // Check clearAux().341  EXPECT_TRUE(LLVMI0->getMetadata("sandboxaux"));342  EXPECT_TRUE(LLVMI1->getMetadata("sandboxaux"));343  Regions[0]->clearAux();344  EXPECT_TRUE(Regions[0]->getAux().empty());345  EXPECT_FALSE(LLVMI0->getMetadata("sandboxaux"));346  EXPECT_FALSE(LLVMI1->getMetadata("sandboxaux"));347}348 349// Check that Aux is well-formed.350TEST_F(RegionTest, AuxVerify) {351  parseIR(C, R"IR(352define void @foo(i8 %v) {353  %t0 = add i8 %v, 0, !sandboxvec !0, !sandboxaux !2354  %t1 = add i8 %v, 1, !sandboxvec !0, !sandboxaux !3355  ret void356}357 358!0 = distinct !{!"sandboxregion"}359!2 = !{i32 0}360!3 = !{i32 2}361)IR");362  llvm::Function *LLVMF = &*M->getFunction("foo");363  sandboxir::Context Ctx(C);364  auto *F = Ctx.createFunction(LLVMF);365  EXPECT_DEBUG_DEATH(sandboxir::Region::createRegionsFromMD(*F, *TTI),366                     ".*Gap*");367}368 369// Check that we get an assertion failure if we try to set the same index more370// than once.371TEST_F(RegionTest, AuxSameIndex) {372  parseIR(C, R"IR(373define void @foo(i8 %v) {374  %t0 = add i8 %v, 0, !sandboxvec !0, !sandboxaux !2375  %t1 = add i8 %v, 1, !sandboxvec !0, !sandboxaux !2376  ret void377}378 379!0 = distinct !{!"sandboxregion"}380!2 = !{i32 0}381)IR");382  llvm::Function *LLVMF = &*M->getFunction("foo");383  sandboxir::Context Ctx(C);384  auto *F = Ctx.createFunction(LLVMF);385  EXPECT_DEBUG_DEATH(sandboxir::Region::createRegionsFromMD(*F, *TTI),386                     ".*already.*");387}388 389// Check that Aux automatically drops instructions that get deleted.390TEST_F(RegionTest, AuxDeleteInstr) {391  parseIR(C, R"IR(392define void @foo(i8 %v) {393  %Add0 = add i8 %v, 0, !sandboxvec !0, !sandboxaux !1394  %Add1 = add i8 %v, 1, !sandboxvec !0, !sandboxaux !2395  %Add2 = add i8 %v, 2, !sandboxvec !0, !sandboxaux !3396  %Add3 = add i8 %v, 2, !sandboxvec !0, !sandboxaux !4397  ret void398}399 400!0 = distinct !{!"sandboxregion"}401!1 = !{i32 0}402!2 = !{i32 1}403!3 = !{i32 2}404!4 = !{i32 3}405)IR");406  llvm::Function *LLVMF = &*M->getFunction("foo");407  sandboxir::Context Ctx(C);408  auto *F = Ctx.createFunction(LLVMF);409  auto *BB = &*F->begin();410  auto It = BB->begin();411  auto *Add0 = &*It++;412  auto *Add1 = &*It++;413  auto *Add2 = &*It++;414  auto *Add3 = &*It++;415  SmallVector<std::unique_ptr<sandboxir::Region>> Regions =416      sandboxir::Region::createRegionsFromMD(*F, *TTI);417  auto &R = *Regions[0];418  EXPECT_THAT(R.getAux(), testing::ElementsAre(Add0, Add1, Add2, Add3));419  // Now delete Add1 and check that Aux contains nullptr instead of Add1.420  Add2->eraseFromParent();421  EXPECT_THAT(R.getAux(), testing::ElementsAre(Add0, Add1, Add3));422  {423    // Check that metadata have also been updated.424    // But first drop Add3 to create a legal Aux vector with no gaps.425    Add3->eraseFromParent();426    SmallVector<std::unique_ptr<sandboxir::Region>> Regions =427        sandboxir::Region::createRegionsFromMD(*F, *TTI);428    EXPECT_THAT(Regions[0]->getAux(), testing::ElementsAre(Add0, Add1));429  }430}431 432TEST_F(RegionTest, AuxWithoutRegion) {433  parseIR(C, R"IR(434define void @foo(i8 %v) {435  %Add0 = add i8 %v, 0, !sandboxaux !0436  ret void437}438!0 = !{i32 0}439)IR");440#ifndef NDEBUG441  llvm::Function *LLVMF = &*M->getFunction("foo");442  sandboxir::Context Ctx(C);443  auto *F = Ctx.createFunction(LLVMF);444  EXPECT_DEATH(sandboxir::Region::createRegionsFromMD(*F, *TTI), "No region.*");445#endif446}447 448TEST_F(RegionTest, AuxRoundTrip) {449  parseIR(C, R"IR(450define i8 @foo(i8 %v0, i8 %v1) {451  %t0 = add i8 %v0, 1452  %t1 = add i8 %t0, %v1453  ret i8 %t1454}455)IR");456  llvm::Function *LLVMF = &*M->getFunction("foo");457  sandboxir::Context Ctx(C);458  auto *F = Ctx.createFunction(LLVMF);459  auto *BB = &*F->begin();460  auto It = BB->begin();461  auto *T0 = cast<sandboxir::Instruction>(&*It++);462  auto *T1 = cast<sandboxir::Instruction>(&*It++);463 464  sandboxir::Region Rgn(Ctx, *TTI);465#ifndef NDEBUG466  EXPECT_DEATH(Rgn.setAux({T0, T0}), ".*already.*");467#endif468  sandboxir::RegionInternalsAttorney::add(Rgn, T0);469  sandboxir::RegionInternalsAttorney::add(Rgn, T1);470  Rgn.setAux({T1, T0});471 472  SmallVector<std::unique_ptr<sandboxir::Region>> Regions =473      sandboxir::Region::createRegionsFromMD(*F, *TTI);474  ASSERT_EQ(1U, Regions.size());475#ifndef NDEBUG476  EXPECT_EQ(Rgn, *Regions[0].get());477#endif478  EXPECT_THAT(Rgn.getAux(), testing::ElementsAre(T1, T0));479}480 481// Same as before but only add instructions to aux. They should get added too482// the region too automatically.483TEST_F(RegionTest, AuxOnlyRoundTrip) {484  parseIR(C, R"IR(485define void @foo(i8 %v) {486  %add0 = add i8 %v, 0487  %add1 = add i8 %v, 1488  ret void489}490)IR");491  llvm::Function *LLVMF = &*M->getFunction("foo");492  sandboxir::Context Ctx(C);493  auto *F = Ctx.createFunction(LLVMF);494  auto *BB = &*F->begin();495  auto It = BB->begin();496  auto *Add0 = cast<sandboxir::Instruction>(&*It++);497  auto *Add1 = cast<sandboxir::Instruction>(&*It++);498 499  sandboxir::Region Rgn(Ctx, *TTI);500#ifndef NDEBUG501  EXPECT_DEATH(Rgn.setAux({Add0, Add0}), ".*already.*");502#endif503  Rgn.setAux({Add1, Add0});504 505  SmallVector<std::unique_ptr<sandboxir::Region>> Regions =506      sandboxir::Region::createRegionsFromMD(*F, *TTI);507  ASSERT_EQ(1U, Regions.size());508#ifndef NDEBUG509  EXPECT_EQ(Rgn, *Regions[0].get());510#endif511  EXPECT_THAT(Rgn.getAux(), testing::ElementsAre(Add1, Add0));512}513