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