brintos

brintos / llvm-project-archived public Read only

0
0
Text · 26.3 KiB · a7d8b6c Raw
807 lines · cpp
1//===- InjectorIRStrategyTest.cpp - Tests for injector strategy -----------===//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/ADT/DenseMap.h"10#include "llvm/ADT/StringRef.h"11#include "llvm/AsmParser/Parser.h"12#include "llvm/AsmParser/SlotMapping.h"13#include "llvm/FuzzMutate/IRMutator.h"14#include "llvm/FuzzMutate/Operations.h"15#include "llvm/FuzzMutate/RandomIRBuilder.h"16#include "llvm/IR/FMF.h"17#include "llvm/IR/Instructions.h"18#include "llvm/IR/LLVMContext.h"19#include "llvm/IR/Module.h"20#include "llvm/IR/Verifier.h"21#include "llvm/Support/SourceMgr.h"22#include <random>23 24#include "gtest/gtest.h"25 26using namespace llvm;27 28static constexpr int Seed = 5;29 30namespace {31 32std::unique_ptr<IRMutator> createInjectorMutator() {33  std::vector<TypeGetter> Types{34      Type::getInt1Ty,  Type::getInt8Ty,  Type::getInt16Ty, Type::getInt32Ty,35      Type::getInt64Ty, Type::getFloatTy, Type::getDoubleTy};36 37  // Add vector 1, 2, 3, 4, and 8.38  int VectorLength[] = {1, 2, 3, 4, 8};39  std::vector<TypeGetter> BasicTypeGetters(Types);40  for (auto typeGetter : BasicTypeGetters) {41    for (int length : VectorLength) {42      Types.push_back([typeGetter, length](LLVMContext &C) {43        return VectorType::get(typeGetter(C), length, false);44      });45    }46  }47 48  std::vector<std::unique_ptr<IRMutationStrategy>> Strategies;49  Strategies.push_back(std::make_unique<InjectorIRStrategy>(50      InjectorIRStrategy::getDefaultOps()));51 52  return std::make_unique<IRMutator>(std::move(Types), std::move(Strategies));53}54 55template <class Strategy> std::unique_ptr<IRMutator> createMutator() {56  std::vector<TypeGetter> Types{57      Type::getInt1Ty,  Type::getInt8Ty,  Type::getInt16Ty, Type::getInt32Ty,58      Type::getInt64Ty, Type::getFloatTy, Type::getDoubleTy};59 60  std::vector<std::unique_ptr<IRMutationStrategy>> Strategies;61  Strategies.push_back(std::make_unique<Strategy>());62 63  return std::make_unique<IRMutator>(std::move(Types), std::move(Strategies));64}65 66std::unique_ptr<Module> parseAssembly(const char *Assembly,67                                      LLVMContext &Context) {68 69  SMDiagnostic Error;70  std::unique_ptr<Module> M = parseAssemblyString(Assembly, Error, Context);71 72  std::string ErrMsg;73  raw_string_ostream OS(ErrMsg);74  Error.print("", OS);75 76  assert(M && !verifyModule(*M, &errs()));77  return M;78}79 80void IterateOnSource(StringRef Source, IRMutator &Mutator) {81  LLVMContext Ctx;82 83  for (int i = 0; i < 10; ++i) {84    auto M = parseAssembly(Source.data(), Ctx);85    ASSERT_TRUE(M && !verifyModule(*M, &errs()));86 87    Mutator.mutateModule(*M, Seed, IRMutator::getModuleSize(*M) + 100);88    EXPECT_TRUE(!verifyModule(*M, &errs()));89  }90}91 92using ModuleVerifier = std::function<void(Module &)>;93 94static void95mutateAndVerifyModule(StringRef Source, std::unique_ptr<IRMutator> &Mutator,96                      int repeat = 100,97                      ArrayRef<ModuleVerifier> ExtraModuleVerifiers = {}) {98  LLVMContext Ctx;99  auto M = parseAssembly(Source.data(), Ctx);100  std::mt19937 mt(Seed);101  std::uniform_int_distribution<int> RandInt(INT_MIN, INT_MAX);102  for (int i = 0; i < repeat; i++) {103    Mutator->mutateModule(*M, RandInt(mt), IRMutator::getModuleSize(*M) + 1024);104    ASSERT_FALSE(verifyModule(*M, &errs()));105    for (auto &ModuleVerifier : ExtraModuleVerifiers) {106      ModuleVerifier(*M);107    }108  }109}110 111template <class Strategy>112static void113mutateAndVerifyModule(StringRef Source, int repeat = 100,114                      ArrayRef<ModuleVerifier> ExtraModuleVerifiers = {}) {115  auto Mutator = createMutator<Strategy>();116  ASSERT_TRUE(Mutator);117  mutateAndVerifyModule(Source, Mutator, repeat, ExtraModuleVerifiers);118}119 120TEST(InjectorIRStrategyTest, EmptyModule) {121  // Test that we can inject into empty module122 123  LLVMContext Ctx;124  auto M = std::make_unique<Module>("M", Ctx);125  ASSERT_TRUE(M && !verifyModule(*M, &errs()));126 127  auto Mutator = createInjectorMutator();128  ASSERT_TRUE(Mutator);129 130  Mutator->mutateModule(*M, Seed, IRMutator::getModuleSize(*M) + 1);131  EXPECT_TRUE(!verifyModule(*M, &errs()));132}133 134TEST(InjectorIRStrategyTest, LargeInsertion) {135  StringRef Source = "";136  auto Mutator = createInjectorMutator();137  ASSERT_TRUE(Mutator);138  mutateAndVerifyModule(Source, Mutator, 100);139}140 141TEST(InjectorIRStrategyTest, InsertWMustTailCall) {142  StringRef Source = "\n\143        define i1 @recursive() {    \n\144        Entry:     \n\145            %Ret = musttail call i1 @recursive() \n\146            ret i1 %Ret \n\147        }";148  auto Mutator = createInjectorMutator();149  ASSERT_TRUE(Mutator);150  mutateAndVerifyModule(Source, Mutator, 100);151}152 153TEST(InjectorIRStrategyTest, InsertWTailCall) {154  StringRef Source = "\n\155        define i1 @recursive() {    \n\156        Entry:     \n\157            %Ret = tail call i1 @recursive() \n\158            ret i1 %Ret \n\159        }";160  auto Mutator = createInjectorMutator();161  ASSERT_TRUE(Mutator);162  mutateAndVerifyModule(Source, Mutator, 100);163}164 165TEST(InstDeleterIRStrategyTest, EmptyFunction) {166  // Test that we don't crash even if we can't remove from one of the functions.167 168  StringRef Source = ""169                     "define <8 x i32> @func1() {\n"170                     "ret <8 x i32> undef\n"171                     "}\n"172                     "\n"173                     "define i32 @func2() {\n"174                     "%A9 = alloca i32\n"175                     "%L6 = load i32, i32* %A9\n"176                     "ret i32 %L6\n"177                     "}\n";178 179  auto Mutator = createMutator<InstDeleterIRStrategy>();180  ASSERT_TRUE(Mutator);181 182  IterateOnSource(Source, *Mutator);183}184 185TEST(InstDeleterIRStrategyTest, PhiNodes) {186  // Test that inst deleter works correctly with the phi nodes.187 188  LLVMContext Ctx;189  StringRef Source = "\n\190      define i32 @earlyreturncrash(i32 %x) {\n\191      entry:\n\192        switch i32 %x, label %sw.epilog [\n\193          i32 1, label %sw.bb1\n\194        ]\n\195      \n\196      sw.bb1:\n\197        br label %sw.epilog\n\198      \n\199      sw.epilog:\n\200        %a.0 = phi i32 [ 7, %entry ],  [ 9, %sw.bb1 ]\n\201        %b.0 = phi i32 [ 10, %entry ], [ 4, %sw.bb1 ]\n\202        ret i32 %a.0\n\203      }";204 205  auto Mutator = createMutator<InstDeleterIRStrategy>();206  ASSERT_TRUE(Mutator);207 208  IterateOnSource(Source, *Mutator);209}210 211static void checkModifyNoUnsignedAndNoSignedWrap(StringRef Opc) {212  LLVMContext Ctx;213  std::string Source = std::string("\n\214      define i32 @test(i32 %x) {\n\215        %a = ") + Opc.str() +216                       std::string(" i32 %x, 10\n\217        ret i32 %a\n\218      }");219 220  auto Mutator = createMutator<InstModificationIRStrategy>();221  ASSERT_TRUE(Mutator);222 223  auto M = parseAssembly(Source.data(), Ctx);224  auto &F = *M->begin();225  auto *AddI = &*F.begin()->begin();226  ASSERT_TRUE(M && !verifyModule(*M, &errs()));227  bool FoundNUW = false;228  bool FoundNSW = false;229  for (int i = 0; i < 100; ++i) {230    Mutator->mutateModule(*M, Seed + i, IRMutator::getModuleSize(*M) + 100);231    EXPECT_TRUE(!verifyModule(*M, &errs()));232    FoundNUW |= AddI->hasNoUnsignedWrap();233    FoundNSW |= AddI->hasNoSignedWrap();234  }235 236  // The mutator should have added nuw and nsw during some mutations.237  EXPECT_TRUE(FoundNUW);238  EXPECT_TRUE(FoundNSW);239}240TEST(InstModificationIRStrategyTest, Add) {241  checkModifyNoUnsignedAndNoSignedWrap("add");242}243 244TEST(InstModificationIRStrategyTest, Sub) {245  checkModifyNoUnsignedAndNoSignedWrap("sub");246}247 248TEST(InstModificationIRStrategyTest, Mul) {249  checkModifyNoUnsignedAndNoSignedWrap("mul");250}251 252TEST(InstModificationIRStrategyTest, Shl) {253  checkModifyNoUnsignedAndNoSignedWrap("shl");254}255 256TEST(InstModificationIRStrategyTest, ICmp) {257  LLVMContext Ctx;258  StringRef Source = "\n\259      define i1 @test(i32 %x) {\n\260        %a = icmp eq i32 %x, 10\n\261        ret i1 %a\n\262      }";263 264  auto Mutator = createMutator<InstModificationIRStrategy>();265  ASSERT_TRUE(Mutator);266 267  auto M = parseAssembly(Source.data(), Ctx);268  auto &F = *M->begin();269  CmpInst *CI = cast<CmpInst>(&*F.begin()->begin());270  ASSERT_TRUE(M && !verifyModule(*M, &errs()));271  bool FoundNE = false;272  for (int i = 0; i < 100; ++i) {273    Mutator->mutateModule(*M, Seed + i, IRMutator::getModuleSize(*M) + 100);274    EXPECT_TRUE(!verifyModule(*M, &errs()));275    FoundNE |= CI->getPredicate() == CmpInst::ICMP_NE;276  }277 278  EXPECT_TRUE(FoundNE);279}280 281TEST(InstModificationIRStrategyTest, FCmp) {282  LLVMContext Ctx;283  StringRef Source = "\n\284      define i1 @test(float %x) {\n\285        %a = fcmp oeq float %x, 10.0\n\286        ret i1 %a\n\287      }";288 289  auto Mutator = createMutator<InstModificationIRStrategy>();290  ASSERT_TRUE(Mutator);291 292  auto M = parseAssembly(Source.data(), Ctx);293  auto &F = *M->begin();294  CmpInst *CI = cast<CmpInst>(&*F.begin()->begin());295  ASSERT_TRUE(M && !verifyModule(*M, &errs()));296  bool FoundONE = false;297  for (int i = 0; i < 100; ++i) {298    Mutator->mutateModule(*M, Seed + i, IRMutator::getModuleSize(*M) + 100);299    EXPECT_TRUE(!verifyModule(*M, &errs()));300    FoundONE |= CI->getPredicate() == CmpInst::FCMP_ONE;301  }302 303  EXPECT_TRUE(FoundONE);304}305 306TEST(InstModificationIRStrategyTest, GEP) {307  LLVMContext Ctx;308  StringRef Source = "\n\309      define i32* @test(i32* %ptr) {\n\310        %gep = getelementptr i32, i32* %ptr, i32 10\n\311        ret i32* %gep\n\312      }";313 314  auto Mutator = createMutator<InstModificationIRStrategy>();315  ASSERT_TRUE(Mutator);316 317  auto M = parseAssembly(Source.data(), Ctx);318  auto &F = *M->begin();319  GetElementPtrInst *GEP = cast<GetElementPtrInst>(&*F.begin()->begin());320  ASSERT_TRUE(M && !verifyModule(*M, &errs()));321  bool FoundInbounds = false;322  for (int i = 0; i < 100; ++i) {323    Mutator->mutateModule(*M, Seed + i, IRMutator::getModuleSize(*M) + 100);324    EXPECT_TRUE(!verifyModule(*M, &errs()));325    FoundInbounds |= GEP->isInBounds();326  }327 328  EXPECT_TRUE(FoundInbounds);329}330 331/// The caller has to guarantee that function argument are used in the SAME332/// place as the operand.333void VerfyOperandShuffled(StringRef Source, std::pair<int, int> ShuffleItems) {334  LLVMContext Ctx;335  auto Mutator = createMutator<InstModificationIRStrategy>();336  ASSERT_TRUE(Mutator);337 338  auto M = parseAssembly(Source.data(), Ctx);339  auto &F = *M->begin();340  Instruction *Inst = &*F.begin()->begin();341  ASSERT_TRUE(M && !verifyModule(*M, &errs()));342  ASSERT_TRUE(Inst->getOperand(ShuffleItems.first) ==343              dyn_cast<Value>(F.getArg(ShuffleItems.first)));344  ASSERT_TRUE(Inst->getOperand(ShuffleItems.second) ==345              dyn_cast<Value>(F.getArg(ShuffleItems.second)));346 347  Mutator->mutateModule(*M, 0, IRMutator::getModuleSize(*M) + 100);348  ASSERT_TRUE(!verifyModule(*M, &errs()));349 350  ASSERT_TRUE(Inst->getOperand(ShuffleItems.first) ==351              dyn_cast<Value>(F.getArg(ShuffleItems.second)));352  ASSERT_TRUE(Inst->getOperand(ShuffleItems.second) ==353              dyn_cast<Value>(F.getArg(ShuffleItems.first)));354}355 356TEST(InstModificationIRStrategyTest, ShuffleAnd) {357  StringRef Source = "\n\358      define i32 @test(i32 %0, i32 %1) {\n\359        %add = and i32 %0, %1\n\360        ret i32 %add\n\361      }";362  VerfyOperandShuffled(Source, {0, 1});363}364TEST(InstModificationIRStrategyTest, ShuffleSelect) {365  StringRef Source = "\n\366      define i32 @test(i1 %0, i32 %1, i32 %2) {\n\367        %select = select i1 %0, i32 %1, i32 %2\n\368        ret i32 %select\n\369      }";370  VerfyOperandShuffled(Source, {1, 2});371}372 373void VerfyDivDidntShuffle(StringRef Source) {374  LLVMContext Ctx;375  auto Mutator = createMutator<InstModificationIRStrategy>();376  ASSERT_TRUE(Mutator);377 378  auto M = parseAssembly(Source.data(), Ctx);379  auto &F = *M->begin();380  Instruction *Inst = &*F.begin()->begin();381  ASSERT_TRUE(M && !verifyModule(*M, &errs()));382 383  EXPECT_TRUE(isa<Constant>(Inst->getOperand(0)));384  EXPECT_TRUE(Inst->getOperand(1) == dyn_cast<Value>(F.getArg(0)));385 386  Mutator->mutateModule(*M, Seed, IRMutator::getModuleSize(*M) + 100);387  EXPECT_TRUE(!verifyModule(*M, &errs()));388 389  // Didn't shuffle.390  EXPECT_TRUE(isa<Constant>(Inst->getOperand(0)));391  EXPECT_TRUE(Inst->getOperand(1) == dyn_cast<Value>(F.getArg(0)));392}393TEST(InstModificationIRStrategyTest, DidntShuffleSDiv) {394  StringRef Source = "\n\395      define i32 @test(i32 %0) {\n\396        %div = sdiv i32 0, %0\n\397        ret i32 %div\n\398      }";399  VerfyDivDidntShuffle(Source);400}401TEST(InstModificationIRStrategyTest, DidntShuffleFRem) {402  StringRef Source = "\n\403      define <2 x double> @test(<2 x double> %0) {\n\404        %div = frem <2 x double> <double 0.0, double 0.0>, %0\n\405        ret <2 x double> %div\n\406      }";407  VerfyDivDidntShuffle(Source);408}409 410TEST(InsertFunctionStrategy, Func) {411  LLVMContext Ctx;412  const char *Source = "";413  auto Mutator = createMutator<InsertFunctionStrategy>();414  ASSERT_TRUE(Mutator);415 416  auto M = parseAssembly(Source, Ctx);417  srand(Seed);418  for (int i = 0; i < 100; i++) {419    Mutator->mutateModule(*M, rand(), 1024);420    EXPECT_TRUE(!verifyModule(*M, &errs()));421  }422}423 424TEST(InsertFunctionStrategy, AvoidCallingFunctionWithSpecialParam) {425  LLVMContext Ctx;426  StringRef Source = "\n\427      declare void @llvm.dbg.value(metadata %0, metadata %1, metadata %2)\n\428      declare i1 @llvm.experimental.gc.result.i1(token %0)\n\429      define i32 @test(i32 %0) gc \"statepoint-example\" {\n\430        ret i32 %0 \n\431      }";432  auto Mutator = createMutator<InsertFunctionStrategy>();433  auto M = parseAssembly(Source.data(), Ctx);434  srand(Seed);435  for (int i = 0; i < 100; i++) {436    Mutator->mutateModule(*M, rand(), 1024);437    EXPECT_TRUE(!verifyModule(*M, &errs()));438  }439}440 441TEST(InstModificationIRStrategy, Exact) {442  LLVMContext Ctx;443  StringRef Source = "\n\444      define i32 @test(i32 %a, i32 %b) {\n\445        %c = ashr i32 %a, %b \n\446        ret i32 %c\n\447      }";448 449  auto Mutator = createMutator<InstModificationIRStrategy>();450  ASSERT_TRUE(Mutator);451 452  std::unique_ptr<Module> M = parseAssembly(Source.data(), Ctx);453  std::mt19937 mt(Seed);454  std::uniform_int_distribution<int> RandInt(INT_MIN, INT_MAX);455  auto &F = *M->begin();456  BinaryOperator *AShr = cast<BinaryOperator>(&*F.begin()->begin());457  bool FoundExact = false;458  for (int i = 0; i < 100; ++i) {459    Mutator->mutateModule(*M, RandInt(mt), IRMutator::getModuleSize(*M) + 100);460    ASSERT_FALSE(verifyModule(*M, &errs()));461    FoundExact |= AShr->isExact();462  }463 464  EXPECT_TRUE(FoundExact);465}466TEST(InstModificationIRStrategy, FastMath) {467  LLVMContext Ctx;468  StringRef Source = "\n\469      declare [4 x <4 x double>] @vecdouble(double)  \n\470      define double @test(i1 %C, double %a, double %b) {  \n\471      Entry:  \n\472        br i1 %C, label %True, label %False  \n\473      True:  \n\474        br label %Exit  \n\475      False:  \n\476        br label %Exit  \n\477      Exit:  \n\478        %PHIi32 = phi i32 [1, %True], [2, %False]  \n\479        %PHIdouble = phi double [%a, %True], [%b, %False]  \n\480        %Call = call [4 x <4 x double>] @vecdouble(double %PHIdouble)  \n\481        %c = fneg double %PHIdouble  \n\482        %s = select i1 %C, double %a, double %b  \n\483        %d = fadd double %s, %c  \n\484        ret double %d \n\485      }";486 487  auto Mutator = createMutator<InstModificationIRStrategy>();488  ASSERT_TRUE(Mutator);489 490  std::unique_ptr<Module> M = parseAssembly(Source.data(), Ctx);491  std::mt19937 mt(Seed);492  std::uniform_int_distribution<int> RandInt(INT_MIN, INT_MAX);493  DenseMap<Instruction *, bool> FPOpsHasFastMath;494  for (auto &F : *M) {495    for (auto &BB : F) {496      for (auto &I : BB) {497        Type *Ty = I.getType();498        if (Ty->isFPOrFPVectorTy() || Ty->isArrayTy()) {499          FPOpsHasFastMath[&I] = false;500        }501      }502    }503  }504  ASSERT_TRUE(M && !verifyModule(*M, &errs()));505  for (int i = 0; i < 300; ++i) {506    Mutator->mutateModule(*M, RandInt(mt), IRMutator::getModuleSize(*M) + 100);507    for (auto p : FPOpsHasFastMath)508      FPOpsHasFastMath[p.first] |= p.first->getFastMathFlags().any();509    ASSERT_FALSE(verifyModule(*M, &errs()));510  }511  for (auto p : FPOpsHasFastMath)512    ASSERT_TRUE(p.second);513}514 515TEST(InsertCFGStrategy, CFG) {516  StringRef Source = "\n\517      define i32 @test(i1 %C1, i1 %C2, i1 %C3, i16 %S1, i16 %S2, i32 %I1) { \n\518        Entry:  \n\519         %I2 = add i32 %I1, 1 \n\520          %C = and i1 %C1, %C2 \n\521        br label %Body \n\522        Body: \n\523         %IB = add i32 %I1, %I2 \n\524          %CB = and i1 %C1, %C \n\525        br label %Exit \n\526        Exit: \n\527          %IE = add i32 %IB, %I2 \n\528          %CE = and i1 %CB, %C \n\529         ret i32 %IE \n\530      }";531  mutateAndVerifyModule<InsertCFGStrategy>(Source);532}533 534TEST(InsertPHIStrategy, PHI) {535  StringRef Source = "\n\536        define void @test(i1 %C1, i1 %C2, i32 %I, double %FP) { \n\537        Entry:  \n\538          %C = and i1 %C1, %C2 \n\539          br i1 %C, label %LoopHead, label %Exit \n\540        LoopHead: ; pred Entry, LoopBody \n\541          switch i32 %I, label %Default [ \n\542              i32 1, label %OnOne  \n\543              i32 2, label %OnTwo \n\544              i32 3, label %OnThree \n\545          ] \n\546        Default:  \n\547          br label %LoopBody \n\548        OnOne: ; pred LoopHead \n\549          %DFP = fmul double %FP, 2.0 \n\550          %OnOneCond = fcmp ogt double %DFP, %FP \n\551          br i1 %OnOneCond, label %LoopBody, label %Exit \n\552        OnTwo: ; pred Entry \n\553          br i1 %C1, label %OnThree, label %LoopBody \n\554        OnThree: ; pred Entry, OnTwo, OnThree \n\555          br i1 %C2, label %OnThree, label %LoopBody \n\556        LoopBody: ; pred Default, OnOne, OnTwo, OnThree \n\557          br label %LoopHead \n\558        Exit: ; pred Entry, OnOne \n\559          ret void \n\560        }";561  mutateAndVerifyModule<InsertPHIStrategy>(Source);562}563 564TEST(InsertPHIStrategy, PHIWithSameIncomingBlock) {565  LLVMContext Ctx;566  StringRef Source = "\n\567        define void @test(i32 %I) { \n\568        Entry:  \n\569          switch i32 %I, label %Exit [ \n\570              i32 1, label %IdentCase  \n\571              i32 2, label %IdentCase \n\572              i32 3, label %IdentCase \n\573              i32 4, label %IdentCase \n\574          ] \n\575        IdentCase: \n\576          br label %Exit \n\577        Exit: \n\578          ret void \n\579        }";580  auto IPS = std::make_unique<InsertPHIStrategy>();581  RandomIRBuilder IB(Seed, {IntegerType::getInt32Ty(Ctx)});582  auto M = parseAssembly(Source.data(), Ctx);583  Function &F = *M->begin();584  for (auto &BB : F) {585    IPS->mutate(BB, IB);586    ASSERT_FALSE(verifyModule(*M, &errs()));587  }588}589 590TEST(SinkInstructionStrategy, Operand) {591  StringRef Source = "\n\592      define i32 @test(i1 %C1, i1 %C2, i1 %C3, i32 %I, i32 %J) { \n\593        Entry:  \n\594          %I100 = add i32 %I, 100  \n\595          switch i32 %I100, label %BB0 [ \n\596            i32 42, label %BB1  \n\597          ] \n\598        BB0:  \n\599          %IAJ = add i32 %I, %J  \n\600          %ISJ = sub i32 %I, %J  \n\601          br label %Exit  \n\602        BB1:  \n\603          %IJ = mul i32 %I, %J  \n\604          %C = and i1 %C2, %C3  \n\605          br i1 %C, label %BB0, label %Exit  \n\606        Exit:  \n\607          ret i32 %I  \n\608      }";609  mutateAndVerifyModule<SinkInstructionStrategy>(Source);610}611 612TEST(SinkInstructionStrategy, DoNotSinkTokenType) {613  StringRef Source = "\n\614      declare ptr @fake_personality_function() \n\615      declare token @llvm.experimental.gc.statepoint.p0(i64 immarg %0, i32 immarg %1, ptr %2, i32 immarg %3, i32 immarg %4, ...) \n\616      define void @test() gc \"statepoint-example\" personality ptr @fake_personality_function { \n\617      Entry: \n\618        %token1 = call token (i64, i32, ptr, i32, i32, ...) \619          @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(ptr addrspace(1) ()) undef, i32 0, i32 0, i32 0, i32 0) \n\620        ret void \n\621      }";622  mutateAndVerifyModule<SinkInstructionStrategy>(Source);623}624 625static void VerifyBlockShuffle(StringRef Source) {626  LLVMContext Ctx;627  auto Mutator = createMutator<ShuffleBlockStrategy>();628  ASSERT_TRUE(Mutator);629 630  std::unique_ptr<Module> M = parseAssembly(Source.data(), Ctx);631  Function *F = &*M->begin();632  DenseMap<BasicBlock *, int> PreShuffleInstCnt;633  for (BasicBlock &BB : *F) {634    PreShuffleInstCnt.insert({&BB, BB.size()});635  }636  std::mt19937 mt(Seed);637  std::uniform_int_distribution<int> RandInt(INT_MIN, INT_MAX);638  for (int i = 0; i < 100; i++) {639    Mutator->mutateModule(*M, RandInt(mt), IRMutator::getModuleSize(*M) + 1024);640    for (BasicBlock &BB : *F) {641      int PostShuffleIntCnt = BB.size();642      EXPECT_EQ(PostShuffleIntCnt, PreShuffleInstCnt[&BB]);643    }644    EXPECT_FALSE(verifyModule(*M, &errs()));645  }646}647 648TEST(ShuffleBlockStrategy, ShuffleBlocks) {649  StringRef Source = "\n\650        define i64 @test(i1 %0, i1 %1, i1 %2, i32 %3, i32 %4) { \n\651        Entry:  \n\652          %A = alloca i32, i32 8, align 4 \n\653          %E.1 = and i32 %3, %4 \n\654          %E.2 = add i32 %4 , 1 \n\655          %A.GEP.1 = getelementptr i32, ptr %A, i32 0 \n\656          %A.GEP.2 = getelementptr i32, ptr %A.GEP.1, i32 1 \n\657          %L.2 = load i32, ptr %A.GEP.2 \n\658          %L.1 = load i32, ptr %A.GEP.1 \n\659          %E.3 = sub i32 %E.2, %L.1 \n\660          %Cond.1 = icmp eq i32 %E.3, %E.2 \n\661          %Cond.2 = and i1 %0, %1 \n\662          %Cond = or i1 %Cond.1, %Cond.2 \n\663          br i1 %Cond, label %BB0, label %BB1  \n\664        BB0:  \n\665          %Add = add i32 %L.1, %L.2 \n\666          %Sub = sub i32 %L.1, %L.2 \n\667          %Sub.1 = sub i32 %Sub, 12 \n\668          %Cast.1 = bitcast i32 %4 to float \n\669          %Add.2 = add i32 %3, 1 \n\670          %Cast.2 = bitcast i32 %Add.2 to float \n\671          %FAdd = fadd float %Cast.1, %Cast.2 \n\672          %Add.3 = add i32 %L.2, %L.1 \n\673          %Cast.3 = bitcast float %FAdd to i32 \n\674          %Sub.2 = sub i32 %Cast.3, %Sub.1 \n\675          %SExt = sext i32 %Cast.3 to i64 \n\676          %A.GEP.3 = getelementptr i64, ptr %A, i32 1 \n\677          store i64 %SExt, ptr %A.GEP.3 \n\678          br label %Exit  \n\679        BB1:  \n\680          %PHI.1 = phi i32 [0, %Entry] \n\681          %SExt.1 = sext i1 %Cond.2 to i32 \n\682          %SExt.2 = sext i1 %Cond.1 to i32 \n\683          %E.164 = zext i32 %E.1 to i64 \n\684          %E.264 = zext i32 %E.2 to i64 \n\685          %E.1264 = mul i64 %E.164, %E.264 \n\686          %E.12 = trunc i64 %E.1264 to i32 \n\687          %A.GEP.4 = getelementptr i32, ptr %A, i32 2 \n\688          %A.GEP.5 = getelementptr i32, ptr %A.GEP.4, i32 2 \n\689          store i32 %E.12, ptr %A.GEP.5 \n\690          br label %Exit  \n\691        Exit:  \n\692          %PHI.2 = phi i32 [%Add, %BB0], [%E.3, %BB1] \n\693          %PHI.3 = phi i64 [%SExt, %BB0], [%E.1264, %BB1] \n\694          %ZExt = zext i32 %PHI.2 to i64 \n\695          %Add.5 = add i64 %PHI.3, 3 \n\696          ret i64 %Add.5  \n\697      }";698  VerifyBlockShuffle(Source);699}700 701TEST(ShuffleBlockStrategy, ShuffleLoop) {702  StringRef Source = "\n\703    define i32 @foo(i32 %Left, i32 %Right) { \n\704    Entry: \n\705      %LPtr = alloca i32, align 4 \n\706      %RPtr = alloca i32, align 4 \n\707      %RetValPtr = alloca i32, align 4 \n\708      store i32 %Left, ptr %LPtr, align 4 \n\709      store i32 %Right, ptr %RPtr, align 4 \n\710      store i32 0, ptr %RetValPtr, align 4 \n\711      br label %LoopHead \n\712    LoopHead: \n\713      %L = load i32, ptr %LPtr, align 4 \n\714      %R = load i32, ptr %RPtr, align 4 \n\715      %C = icmp slt i32 %L, %R \n\716      br i1 %C, label %LoopBody, label %Exit \n\717    LoopBody: \n\718      %OldL = load i32, ptr %LPtr, align 4 \n\719      %NewL = add nsw i32 %OldL, 1 \n\720      store i32 %NewL, ptr %LPtr, align 4 \n\721      %OldRetVal = load i32, ptr %RetValPtr, align 4 \n\722      %NewRetVal = add nsw i32 %OldRetVal, 1 \n\723      store i32 %NewRetVal, ptr %RetValPtr, align 4 \n\724      br label %LoopHead \n\725    Exit: \n\726      %RetVal = load i32, ptr %RetValPtr, align 4 \n\727      ret i32 %RetVal \n\728    }";729  VerifyBlockShuffle(Source);730}731 732TEST(AllStrategies, SkipEHPad) {733  StringRef Source = "\n\734    define void @f(i32 %x) personality ptr @__CxxFrameHandler3 { \n\735    entry: \n\736      invoke void @g() to label %try.cont unwind label %catch.dispatch \n\737    catch.dispatch: \n\738      %0 = catchswitch within none [label %catch] unwind to caller \n\739    catch: \n\740      %1 = catchpad within %0 [ptr null, i32 64, ptr null] \n\741      catchret from %1 to label %try.cont \n\742    try.cont: \n\743      ret void \n\744    } \n\745    declare void @g() \n\746    declare i32 @__CxxFrameHandler3(...) \n\747    ";748 749  mutateAndVerifyModule<ShuffleBlockStrategy>(Source);750  mutateAndVerifyModule<InsertPHIStrategy>(Source);751  mutateAndVerifyModule<InsertFunctionStrategy>(Source);752  mutateAndVerifyModule<InsertCFGStrategy>(Source);753  mutateAndVerifyModule<SinkInstructionStrategy>(Source);754  mutateAndVerifyModule<InjectorIRStrategy>(Source);755  mutateAndVerifyModule<InstModificationIRStrategy>(Source);756}757 758TEST(AllStrategies, SpecialTerminator) {759  StringRef Source = "\n\760    declare amdgpu_cs_chain void @callee(<3 x i32> inreg, { i32, ptr addrspace(5), i32, i32 })\n\761    define amdgpu_cs_chain void @chain_to_chain(<3 x i32> inreg %sgpr, { i32, ptr addrspace(5), i32, i32 } %vgpr) {\n\762      call void(ptr, i64, <3 x i32>, { i32, ptr addrspace(5), i32, i32 }, i32, ...) @llvm.amdgcn.cs.chain(ptr @callee, i64 -1, <3 x i32> inreg %sgpr, { i32, ptr addrspace(5), i32, i32 } %vgpr, i32 0) \n\763      unreachable\n\764    }\n\765  ";766  mutateAndVerifyModule<InjectorIRStrategy>(Source);767  mutateAndVerifyModule<InsertCFGStrategy>(Source);768  mutateAndVerifyModule<InsertFunctionStrategy>(Source);769  mutateAndVerifyModule<InsertPHIStrategy>(Source);770  mutateAndVerifyModule<InstModificationIRStrategy>(Source);771  mutateAndVerifyModule<ShuffleBlockStrategy>(Source);772  mutateAndVerifyModule<SinkInstructionStrategy>(Source);773}774 775TEST(AllStrategies, AMDGCNLegalAddrspace) {776  StringRef Source = "\n\777    target triple = \"amdgcn-amd-amdhsa\"\n\778    ; minimum values required by the fuzzer (e.g., default addrspace for allocas and globals)\n\779    target datalayout = \"A5-G1\"\n\780    define amdgpu_gfx void @strict_wwm_amdgpu_cs_main(<4 x i32> inreg %desc, i32 %index) {\n\781    %desc.int = bitcast <4 x i32> %desc to i128\n\782    %desc.ptr = inttoptr i128 %desc.int to ptr addrspace(8)\n\783    ret void\n\784  }\n\785  ";786 787  ModuleVerifier AddrSpaceVerifier = [](Module &M) {788    Function *F = M.getFunction("strict_wwm_amdgpu_cs_main");789    EXPECT_TRUE(F != nullptr);790    for (BasicBlock &BB : *F) {791      for (Instruction &I : BB) {792        if (StoreInst *S = dyn_cast<StoreInst>(&I)) {793          EXPECT_TRUE(S->getPointerAddressSpace() != 8);794        } else if (LoadInst *L = dyn_cast<LoadInst>(&I)) {795          EXPECT_TRUE(L->getPointerAddressSpace() != 8);796        }797      }798    }799  };800 801  int Repeat = 100;802  mutateAndVerifyModule<SinkInstructionStrategy>(Source, Repeat,803                                                 {AddrSpaceVerifier});804}805 806} // namespace807