[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;
|
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
|
/// Strategy to select a random instruction and add a new sink (user) to it to
|
||||||
/// increate data dependency.
|
/// increate data dependency.
|
||||||
class SinkInstructionStrategy : public IRMutationStrategy {
|
class SinkInstructionStrategy : public IRMutationStrategy {
|
||||||
|
|
|
@ -61,6 +61,8 @@ struct RandomIRBuilder {
|
||||||
ArrayRef<Value *> Srcs, fuzzerop::SourcePred Pred);
|
ArrayRef<Value *> Srcs, fuzzerop::SourcePred Pred);
|
||||||
Type *chooseType(LLVMContext &Context, ArrayRef<Value *> Srcs,
|
Type *chooseType(LLVMContext &Context, ArrayRef<Value *> Srcs,
|
||||||
fuzzerop::SourcePred Pred);
|
fuzzerop::SourcePred Pred);
|
||||||
|
/// Return a uniformly choosen type from \c AllowedTypes
|
||||||
|
Type *randomType();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace llvm
|
} // namespace llvm
|
||||||
|
|
|
@ -299,6 +299,35 @@ void InstModificationIRStrategy::mutate(Instruction &Inst,
|
||||||
RS.getSelection()();
|
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) {
|
void SinkInstructionStrategy::mutate(Function &F, RandomIRBuilder &IB) {
|
||||||
for (BasicBlock &BB : F) {
|
for (BasicBlock &BB : F) {
|
||||||
this->mutate(BB, IB);
|
this->mutate(BB, IB);
|
||||||
|
|
|
@ -169,3 +169,8 @@ Value *RandomIRBuilder::findPointer(BasicBlock &BB,
|
||||||
return RS.getSelection();
|
return RS.getSelection();
|
||||||
return nullptr;
|
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/AsmParser/SlotMapping.h"
|
||||||
#include "llvm/FuzzMutate/IRMutator.h"
|
#include "llvm/FuzzMutate/IRMutator.h"
|
||||||
#include "llvm/FuzzMutate/Operations.h"
|
#include "llvm/FuzzMutate/Operations.h"
|
||||||
|
#include "llvm/FuzzMutate/RandomIRBuilder.h"
|
||||||
#include "llvm/IR/Instructions.h"
|
#include "llvm/IR/Instructions.h"
|
||||||
#include "llvm/IR/LLVMContext.h"
|
#include "llvm/IR/LLVMContext.h"
|
||||||
#include "llvm/IR/Module.h"
|
#include "llvm/IR/Module.h"
|
||||||
|
@ -310,6 +311,72 @@ TEST(InstModificationIRStrategyTest, DidntShuffleFRem) {
|
||||||
VerfyDivDidntShuffle(Source);
|
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) {
|
TEST(SinkInstructionStrategy, Operand) {
|
||||||
LLVMContext Ctx;
|
LLVMContext Ctx;
|
||||||
StringRef Source = "\n\
|
StringRef Source = "\n\
|
||||||
|
|
Loading…
Reference in New Issue