brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.5 KiB · 1a32702 Raw
352 lines · cpp
1//===- PassTest.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/Pass.h"10#include "llvm/Analysis/TargetTransformInfo.h"11#include "llvm/AsmParser/Parser.h"12#include "llvm/IR/Module.h"13#include "llvm/SandboxIR/Constant.h"14#include "llvm/SandboxIR/Context.h"15#include "llvm/SandboxIR/Function.h"16#include "llvm/SandboxIR/PassManager.h"17#include "llvm/SandboxIR/Region.h"18#include "llvm/Support/SourceMgr.h"19#include "gtest/gtest.h"20 21using namespace llvm::sandboxir;22 23struct PassTest : public testing::Test {24  llvm::LLVMContext LLVMCtx;25  std::unique_ptr<llvm::Module> LLVMM;26  std::unique_ptr<Context> Ctx;27  std::unique_ptr<llvm::TargetTransformInfo> TTI;28 29  Function *parseFunction(const char *IR, const char *FuncName) {30    llvm::SMDiagnostic Err;31    LLVMM = parseAssemblyString(IR, Err, LLVMCtx);32    TTI = std::make_unique<llvm::TargetTransformInfo>(LLVMM->getDataLayout());33 34    if (!LLVMM)35      Err.print("PassTest", llvm::errs());36    Ctx = std::make_unique<Context>(LLVMCtx);37    return Ctx->createFunction(LLVMM->getFunction(FuncName));38  }39};40 41TEST_F(PassTest, FunctionPass) {42  auto *F = parseFunction(R"IR(43define void @foo() {44  ret void45}46)IR",47                          "foo");48  class TestPass final : public FunctionPass {49    unsigned &BBCnt;50 51  public:52    TestPass(unsigned &BBCnt) : FunctionPass("test-pass"), BBCnt(BBCnt) {}53    bool runOnFunction(Function &F, const Analyses &A) final {54      for ([[maybe_unused]] auto &BB : F)55        ++BBCnt;56      return false;57    }58  };59  unsigned BBCnt = 0;60  TestPass TPass(BBCnt);61  // Check getName(),62  EXPECT_EQ(TPass.getName(), "test-pass");63  // Check classof().64  EXPECT_TRUE(llvm::isa<FunctionPass>(TPass));65  // Check runOnFunction();66  TPass.runOnFunction(*F, Analyses::emptyForTesting());67  EXPECT_EQ(BBCnt, 1u);68#ifndef NDEBUG69  {70    // Check print().71    std::string Buff;72    llvm::raw_string_ostream SS(Buff);73    TPass.print(SS);74    EXPECT_EQ(Buff, "test-pass");75  }76  {77    // Check operator<<().78    std::string Buff;79    llvm::raw_string_ostream SS(Buff);80    SS << TPass;81    EXPECT_EQ(Buff, "test-pass");82  }83  // Check pass name assertions.84  class TestNamePass final : public FunctionPass {85  public:86    TestNamePass(llvm::StringRef Name) : FunctionPass(Name) {}87    bool runOnFunction(Function &F, const Analyses &A) override {88      return false;89    }90  };91  EXPECT_DEATH(TestNamePass("white space"), ".*whitespace.*");92  EXPECT_DEATH(TestNamePass("-dash"), ".*start with.*");93#endif94}95 96TEST_F(PassTest, RegionPass) {97  auto *F = parseFunction(R"IR(98define i8 @foo(i8 %v0, i8 %v1) {99  %t0 = add i8 %v0, 1100  %t1 = add i8 %t0, %v1, !sandboxvec !0101  %t2 = add i8 %t1, %v1, !sandboxvec !0102  ret i8 %t1103}104 105!0 = distinct !{!"sandboxregion"}106)IR",107                          "foo");108 109  class TestPass final : public RegionPass {110    unsigned &InstCount;111 112  public:113    TestPass(unsigned &InstCount)114        : RegionPass("test-pass"), InstCount(InstCount) {}115    bool runOnRegion(Region &R, const Analyses &A) final {116      for ([[maybe_unused]] auto &Inst : R) {117        ++InstCount;118      }119      return false;120    }121  };122  unsigned InstCount = 0;123  TestPass TPass(InstCount);124  // Check getName(),125  EXPECT_EQ(TPass.getName(), "test-pass");126  // Check runOnRegion();127  llvm::SmallVector<std::unique_ptr<Region>> Regions =128      Region::createRegionsFromMD(*F, *TTI);129  ASSERT_EQ(Regions.size(), 1u);130  TPass.runOnRegion(*Regions[0], Analyses::emptyForTesting());131  EXPECT_EQ(InstCount, 2u);132#ifndef NDEBUG133  {134    // Check print().135    std::string Buff;136    llvm::raw_string_ostream SS(Buff);137    TPass.print(SS);138    EXPECT_EQ(Buff, "test-pass");139  }140  {141    // Check operator<<().142    std::string Buff;143    llvm::raw_string_ostream SS(Buff);144    SS << TPass;145    EXPECT_EQ(Buff, "test-pass");146  }147  // Check pass name assertions.148  class TestNamePass final : public RegionPass {149  public:150    TestNamePass(llvm::StringRef Name) : RegionPass(Name) {}151    bool runOnRegion(Region &F, const Analyses &A) override { return false; }152  };153  EXPECT_DEATH(TestNamePass("white space"), ".*whitespace.*");154  EXPECT_DEATH(TestNamePass("-dash"), ".*start with.*");155#endif156}157 158TEST_F(PassTest, FunctionPassManager) {159  auto *F = parseFunction(R"IR(160define void @foo() {161  ret void162}163)IR",164                          "foo");165  class TestPass1 final : public FunctionPass {166    unsigned &BBCnt;167 168  public:169    TestPass1(unsigned &BBCnt) : FunctionPass("test-pass1"), BBCnt(BBCnt) {}170    bool runOnFunction(Function &F, const Analyses &A) final {171      for ([[maybe_unused]] auto &BB : F)172        ++BBCnt;173      return false;174    }175  };176  class TestPass2 final : public FunctionPass {177    unsigned &BBCnt;178 179  public:180    TestPass2(unsigned &BBCnt) : FunctionPass("test-pass2"), BBCnt(BBCnt) {}181    bool runOnFunction(Function &F, const Analyses &A) final {182      for ([[maybe_unused]] auto &BB : F)183        ++BBCnt;184      return false;185    }186  };187  unsigned BBCnt1 = 0;188  unsigned BBCnt2 = 0;189 190  FunctionPassManager FPM("test-fpm");191  FPM.addPass(std::make_unique<TestPass1>(BBCnt1));192  FPM.addPass(std::make_unique<TestPass2>(BBCnt2));193  // Check runOnFunction().194  FPM.runOnFunction(*F, Analyses::emptyForTesting());195  EXPECT_EQ(BBCnt1, 1u);196  EXPECT_EQ(BBCnt2, 1u);197#ifndef NDEBUG198  // Check dump().199  std::string Buff;200  llvm::raw_string_ostream SS(Buff);201  FPM.print(SS);202  EXPECT_EQ(Buff, "test-fpm<test-pass1,test-pass2>");203#endif // NDEBUG204}205 206TEST_F(PassTest, RegionPassManager) {207  auto *F = parseFunction(R"IR(208define i8 @foo(i8 %v0, i8 %v1) {209  %t0 = add i8 %v0, 1210  %t1 = add i8 %t0, %v1, !sandboxvec !0211  %t2 = add i8 %t1, %v1, !sandboxvec !0212  ret i8 %t1213}214 215!0 = distinct !{!"sandboxregion"}216)IR",217                          "foo");218 219  class TestPass1 final : public RegionPass {220    unsigned &InstCount;221 222  public:223    TestPass1(unsigned &InstCount)224        : RegionPass("test-pass1"), InstCount(InstCount) {}225    bool runOnRegion(Region &R, const Analyses &A) final {226      for ([[maybe_unused]] auto &Inst : R)227        ++InstCount;228      return false;229    }230  };231  class TestPass2 final : public RegionPass {232    unsigned &InstCount;233 234  public:235    TestPass2(unsigned &InstCount)236        : RegionPass("test-pass2"), InstCount(InstCount) {}237    bool runOnRegion(Region &R, const Analyses &A) final {238      for ([[maybe_unused]] auto &Inst : R)239        ++InstCount;240      return false;241    }242  };243  unsigned InstCount1 = 0;244  unsigned InstCount2 = 0;245 246  RegionPassManager RPM("test-rpm");247  RPM.addPass(std::make_unique<TestPass1>(InstCount1));248  RPM.addPass(std::make_unique<TestPass2>(InstCount2));249  // Check runOnRegion().250  llvm::SmallVector<std::unique_ptr<Region>> Regions =251      Region::createRegionsFromMD(*F, *TTI);252  ASSERT_EQ(Regions.size(), 1u);253  RPM.runOnRegion(*Regions[0], Analyses::emptyForTesting());254  EXPECT_EQ(InstCount1, 2u);255  EXPECT_EQ(InstCount2, 2u);256#ifndef NDEBUG257  // Check dump().258  std::string Buff;259  llvm::raw_string_ostream SS(Buff);260  RPM.print(SS);261  EXPECT_EQ(Buff, "test-rpm<test-pass1,test-pass2>");262#endif // NDEBUG263}264 265TEST_F(PassTest, SetPassPipeline) {266  auto *F = parseFunction(R"IR(267define void @f() {268  ret void269}270)IR",271                          "f");272  class FooPass final : public FunctionPass {273    std::string &Str;274    std::string Args;275 276  public:277    FooPass(std::string &Str, llvm::StringRef Args)278        : FunctionPass("foo-pass"), Str(Str), Args(Args.str()) {}279    bool runOnFunction(Function &F, const Analyses &A) final {280      Str += "foo<" + Args + ">";281      return false;282    }283  };284  class BarPass final : public FunctionPass {285    std::string &Str;286    std::string Args;287 288  public:289    BarPass(std::string &Str, llvm::StringRef Args)290        : FunctionPass("bar-pass"), Str(Str), Args(Args.str()) {}291    bool runOnFunction(Function &F, const Analyses &A) final {292      Str += "bar<" + Args + ">";293      return false;294    }295  };296 297  std::string Str;298  auto CreatePass =299      [&Str](llvm::StringRef Name,300             llvm::StringRef Args) -> std::unique_ptr<FunctionPass> {301    if (Name == "foo")302      return std::make_unique<FooPass>(Str, Args);303    if (Name == "bar")304      return std::make_unique<BarPass>(Str, Args);305    return nullptr;306  };307 308  FunctionPassManager FPM("test-fpm");309  FPM.setPassPipeline("foo<abc>,bar<nested1<nested2<nested3>>>,foo",310                      CreatePass);311  FPM.runOnFunction(*F, Analyses::emptyForTesting());312  EXPECT_EQ(Str, "foo<abc>bar<nested1<nested2<nested3>>>foo<>");313 314  // A second call to setPassPipeline will trigger an assertion in debug mode.315#ifndef NDEBUG316  EXPECT_DEATH(FPM.setPassPipeline("bar,bar,foo", CreatePass),317               "setPassPipeline called on a non-empty sandboxir::PassManager");318#endif319 320  // Fresh PM for the death tests so they die from bad pipeline strings, rather321  // than from multiple setPassPipeline calls.322  FunctionPassManager FPM2("test-fpm");323  // Bad/empty pass names.324  EXPECT_DEATH(FPM2.setPassPipeline("bad-pass-name", CreatePass),325               ".*not registered.*");326  EXPECT_DEATH(FPM2.setPassPipeline(",", CreatePass), ".*empty pass name.*");327  EXPECT_DEATH(FPM2.setPassPipeline("<>", CreatePass), ".*empty pass name.*");328  EXPECT_DEATH(FPM2.setPassPipeline("<>foo", CreatePass),329               ".*empty pass name.*");330  EXPECT_DEATH(FPM2.setPassPipeline("foo,<>", CreatePass),331               ".*empty pass name.*");332 333  // Mismatched argument brackets.334  EXPECT_DEATH(FPM2.setPassPipeline("foo<", CreatePass), ".*Missing '>'.*");335  EXPECT_DEATH(FPM2.setPassPipeline("foo<bar", CreatePass), ".*Missing '>'.*");336  EXPECT_DEATH(FPM2.setPassPipeline("foo<bar<>", CreatePass),337               ".*Missing '>'.*");338  EXPECT_DEATH(FPM2.setPassPipeline("foo>", CreatePass), ".*Unexpected '>'.*");339  EXPECT_DEATH(FPM2.setPassPipeline(">foo", CreatePass), ".*Unexpected '>'.*");340  // Extra garbage between args and next delimiter/end-of-string.341  EXPECT_DEATH(FPM2.setPassPipeline("foo<bar<>>>", CreatePass),342               ".*Expected delimiter.*");343  EXPECT_DEATH(FPM2.setPassPipeline("bar<>foo", CreatePass),344               ".*Expected delimiter.*");345  EXPECT_DEATH(FPM2.setPassPipeline("bar<>foo,baz", CreatePass),346               ".*Expected delimiter.*");347  EXPECT_DEATH(FPM2.setPassPipeline("foo<args><more-args>", CreatePass),348               ".*Expected delimiter.*");349  EXPECT_DEATH(FPM2.setPassPipeline("foo<args>bar", CreatePass),350               ".*Expected delimiter.*");351}352