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,17 @@ void mutate(Instruction &Inst, RandomIRBuilder &IB) override; }; +/// Strategy to insert PHI Nodes at the head of each basic block. +class InsertPHIStrategy : public IRMutationStrategy { +public: + uint64_t getWeight(size_t CurrentSize, size_t MaxSize, + uint64_t CurrentWeight) override { + return 2; + } + + void mutate(BasicBlock &BB, 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 { diff --git a/llvm/include/llvm/FuzzMutate/RandomIRBuilder.h b/llvm/include/llvm/FuzzMutate/RandomIRBuilder.h --- a/llvm/include/llvm/FuzzMutate/RandomIRBuilder.h +++ b/llvm/include/llvm/FuzzMutate/RandomIRBuilder.h @@ -61,6 +61,8 @@ ArrayRef Srcs, fuzzerop::SourcePred Pred); Type *chooseType(LLVMContext &Context, ArrayRef Srcs, fuzzerop::SourcePred Pred); + /// Return a uniformly choosen type from \c AllowedTypes + Type *randomType(); }; } // namespace llvm 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,35 @@ RS.getSelection()(); } +void InsertPHIStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) { + // Can't insert PHI node to entry node. + if (&BB == &BB.getParent()->getEntryBlock()) + return; + Type *Ty = IB.randomType(); + PHINode *PHI = PHINode::Create(Ty, llvm::pred_size(&BB), "", &BB.front()); + + // Use a map to make sure the same incoming basic block has the same value. + DenseMap IncomingValues; + for (BasicBlock *Pred : predecessors(&BB)) { + Value *Src = IncomingValues[Pred]; + // If `Pred` is not in the map yet, we'll get a nullptr. + if (!Src) { + SmallVector Insts; + for (auto I = Pred->begin(); I != Pred->end(); ++I) + Insts.push_back(&*I); + // There is no need to inform IB what previously used values are if we are + // using `onlyType` + Src = IB.findOrCreateSource(*Pred, Insts, {}, fuzzerop::onlyType(Ty)); + IncomingValues[Pred] = Src; + } + PHI->addIncoming(Src, Pred); + } + SmallVector InstsAfter; + for (auto I = BB.getFirstInsertionPt(), E = BB.end(); I != E; ++I) + InstsAfter.push_back(&*I); + IB.connectToSink(BB, InstsAfter, PHI); +} + void SinkInstructionStrategy::mutate(Function &F, RandomIRBuilder &IB) { for (BasicBlock &BB : F) { this->mutate(BB, IB); diff --git a/llvm/lib/FuzzMutate/RandomIRBuilder.cpp b/llvm/lib/FuzzMutate/RandomIRBuilder.cpp --- a/llvm/lib/FuzzMutate/RandomIRBuilder.cpp +++ b/llvm/lib/FuzzMutate/RandomIRBuilder.cpp @@ -169,3 +169,8 @@ return RS.getSelection(); return nullptr; } + +Type *RandomIRBuilder::randomType() { + uint64_t TyIdx = uniform(Rand, 0, KnownTypes.size() - 1); + return KnownTypes[TyIdx]; +} 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 @@ -12,6 +12,7 @@ #include "llvm/AsmParser/SlotMapping.h" #include "llvm/FuzzMutate/IRMutator.h" #include "llvm/FuzzMutate/Operations.h" +#include "llvm/FuzzMutate/RandomIRBuilder.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" @@ -310,6 +311,72 @@ VerfyDivDidntShuffle(Source); } +TEST(InsertPHIStrategy, PHI) { + LLVMContext Ctx; + StringRef Source = "\n\ + define void @test(i1 %C1, i1 %C2, i32 %I, double %FP) { \n\ + Entry: \n\ + %C = and i1 %C1, %C2 \n\ + br i1 %C, label %LoopHead, label %Exit \n\ + LoopHead: ; pred Entry, LoopBody \n\ + switch i32 %I, label %Default [ \n\ + i32 1, label %OnOne \n\ + i32 2, label %OnTwo \n\ + i32 3, label %OnThree \n\ + ] \n\ + Default: \n\ + br label %LoopBody \n\ + OnOne: ; pred LoopHead \n\ + %DFP = fmul double %FP, 2.0 \n\ + %OnOneCond = fcmp ogt double %DFP, %FP \n\ + br i1 %OnOneCond, label %LoopBody, label %Exit \n\ + OnTwo: ; pred Entry \n\ + br i1 %C1, label %OnThree, label %LoopBody \n\ + OnThree: ; pred Entry, OnTwo, OnThree \n\ + br i1 %C2, label %OnThree, label %LoopBody \n\ + LoopBody: ; pred Default, OnOne, OnTwo, OnThree \n\ + br label %LoopHead \n\ + Exit: ; pred Entry, OnOne \n\ + ret void \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); + ASSERT_FALSE(verifyModule(*M, &errs())); + } +} + +TEST(InsertPHIStrategy, PHIWithSameIncomingBlock) { + LLVMContext Ctx; + StringRef Source = "\n\ + define void @test(i32 %I) { \n\ + Entry: \n\ + switch i32 %I, label %Exit [ \n\ + i32 1, label %IdentCase \n\ + i32 2, label %IdentCase \n\ + i32 3, label %IdentCase \n\ + i32 4, label %IdentCase \n\ + ] \n\ + IdentCase: \n\ + br label %Exit \n\ + Exit: \n\ + ret void \n\ + }"; + auto IPS = std::make_unique(); + RandomIRBuilder IB(Seed, {IntegerType::getInt32Ty(Ctx)}); + auto M = parseAssembly(Source.data(), Ctx); + Function &F = *M->begin(); + for (auto &BB : F) { + IPS->mutate(BB, IB); + ASSERT_FALSE(verifyModule(*M, &errs())); + } +} + TEST(SinkInstructionStrategy, Operand) { LLVMContext Ctx; StringRef Source = "\n\