diff --git a/llvm/include/llvm/FuzzMutate/IRMutator.h b/llvm/include/llvm/FuzzMutate/IRMutator.h --- a/llvm/include/llvm/FuzzMutate/IRMutator.h +++ b/llvm/include/llvm/FuzzMutate/IRMutator.h @@ -118,6 +118,19 @@ void mutate(Instruction &Inst, RandomIRBuilder &IB) override; }; +/// Strategy to select a random instruction and add a new sink (user) to it to +/// increate data dependency. +class SinkInstructionStrategy : public IRMutationStrategy { +public: + uint64_t getWeight(size_t CurrentSize, size_t MaxSize, + uint64_t CurrentWeight) override { + return 2; + } + + void mutate(Function &F, RandomIRBuilder &IB) override; + void mutate(BasicBlock &BB, RandomIRBuilder &IB) override; +}; + /// Strategy to randomly select a block and shuffle the operations without /// affecting data dependency. class ShuffleBlockStrategy : public IRMutationStrategy { diff --git a/llvm/lib/FuzzMutate/IRMutator.cpp b/llvm/lib/FuzzMutate/IRMutator.cpp --- a/llvm/lib/FuzzMutate/IRMutator.cpp +++ b/llvm/lib/FuzzMutate/IRMutator.cpp @@ -299,6 +299,29 @@ RS.getSelection()(); } +void SinkInstructionStrategy::mutate(Function &F, RandomIRBuilder &IB) { + for (BasicBlock &BB : F) { + this->mutate(BB, IB); + } +} +void SinkInstructionStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) { + SmallVector Insts; + for (auto I = BB.getFirstInsertionPt(), E = BB.end(); I != E; ++I) + Insts.push_back(&*I); + if (Insts.size() < 1) + return; + // Choose an Instruction to mutate. + uint64_t Idx = uniform(IB.Rand, 0, Insts.size() - 1); + Instruction *Inst = Insts[Idx]; + // `Idx + 1` so we don't sink to ourselves. + auto InstsAfter = makeArrayRef(Insts).slice(Idx + 1); + LLVMContext &C = BB.getParent()->getParent()->getContext(); + // Don't sink terminators, void function calls, etc. + if (Inst->getType() != Type::getVoidTy(C)) + // Find a new sink and wire up the results of the operation. + IB.connectToSink(BB, InstsAfter, Inst); +} + void ShuffleBlockStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) { SmallPtrSet AliveInsts; diff --git a/llvm/unittests/FuzzMutate/StrategiesTest.cpp b/llvm/unittests/FuzzMutate/StrategiesTest.cpp --- a/llvm/unittests/FuzzMutate/StrategiesTest.cpp +++ b/llvm/unittests/FuzzMutate/StrategiesTest.cpp @@ -310,6 +310,38 @@ VerfyDivDidntShuffle(Source); } +TEST(SinkInstructionStrategy, Operand) { + LLVMContext Ctx; + StringRef Source = "\n\ + define i32 @test(i1 %C1, i1 %C2, i1 %C3, i32 %I, i32 %J) { \n\ + Entry: \n\ + %I100 = add i32 %I, 100 \n\ + switch i32 %I100, label %BB0 [ \n\ + i32 42, label %BB1 \n\ + ] \n\ + BB0: \n\ + %IAJ = add i32 %I, %J \n\ + %ISJ = sub i32 %I, %J \n\ + br label %Exit \n\ + BB1: \n\ + %IJ = mul i32 %I, %J \n\ + %C = and i1 %C2, %C3 \n\ + br i1 %C, label %BB0, label %Exit \n\ + Exit: \n\ + ret i32 %I \n\ + }"; + auto Mutator = createMutator(); + ASSERT_TRUE(Mutator); + + auto M = parseAssembly(Source.data(), Ctx); + std::mt19937 mt(Seed); + std::uniform_int_distribution RandInt(INT_MIN, INT_MAX); + for (int i = 0; i < 100; i++) { + Mutator->mutateModule(*M, RandInt(mt), Source.size(), Source.size() + 1024); + EXPECT_FALSE(verifyModule(*M, &errs())); + } +} + static void VerifyBlockShuffle(StringRef Source) { LLVMContext Ctx; auto Mutator = createMutator();