[FuzzMutate] New InsertPHINode strategy.
PHI Node can't be modeled like other instructions since its operand number depends on predecessors. So we have a stand alone strategy for it. Signed-off-by: Peter Rong <PeterRong96@gmail.com> Reviewed By: arsenm Differential Revision: https://reviews.llvm.org/D138959
This commit is contained in:
parent
0926035ed5
commit
4be0873471
|
@ -118,6 +118,17 @@ public:
|
|||
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 {
|
||||
|
|
|
@ -61,6 +61,8 @@ struct RandomIRBuilder {
|
|||
ArrayRef<Value *> Srcs, fuzzerop::SourcePred Pred);
|
||||
Type *chooseType(LLVMContext &Context, ArrayRef<Value *> Srcs,
|
||||
fuzzerop::SourcePred Pred);
|
||||
/// Return a uniformly choosen type from \c AllowedTypes
|
||||
Type *randomType();
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
|
|
@ -299,6 +299,35 @@ void InstModificationIRStrategy::mutate(Instruction &Inst,
|
|||
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<BasicBlock *, Value *> 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<Instruction *, 32> 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<Instruction *, 32> 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);
|
||||
|
|
|
@ -169,3 +169,8 @@ Value *RandomIRBuilder::findPointer(BasicBlock &BB,
|
|||
return RS.getSelection();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Type *RandomIRBuilder::randomType() {
|
||||
uint64_t TyIdx = uniform<uint64_t>(Rand, 0, KnownTypes.size() - 1);
|
||||
return KnownTypes[TyIdx];
|
||||
}
|
||||
|
|
|
@ -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 @@ TEST(InstModificationIRStrategyTest, DidntShuffleFRem) {
|
|||
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<InsertPHIStrategy>();
|
||||
ASSERT_TRUE(Mutator);
|
||||
|
||||
auto M = parseAssembly(Source.data(), Ctx);
|
||||
std::mt19937 mt(Seed);
|
||||
std::uniform_int_distribution<int> 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<InsertPHIStrategy>();
|
||||
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\
|
||||
|
|
Loading…
Reference in New Issue