[FuzzMutate] Update InstModifierStrategy

We can randomly switch two operands of an instruction now

Signed-off-by: Peter Rong <PeterRong96@gmail.com>
This commit is contained in:
Peter Rong 2022-11-17 15:12:48 -08:00
parent 06e2b44c46
commit 23481bfe5a
2 changed files with 136 additions and 20 deletions

View File

@ -218,8 +218,8 @@ void InstModificationIRStrategy::mutate(Instruction &Inst,
case Instruction::Mul:
case Instruction::Sub:
case Instruction::Shl:
Modifications.push_back([&Inst]() { Inst.setHasNoSignedWrap(true); }),
Modifications.push_back([&Inst]() { Inst.setHasNoSignedWrap(false); });
Modifications.push_back([&Inst]() { Inst.setHasNoSignedWrap(true); });
Modifications.push_back([&Inst]() { Inst.setHasNoSignedWrap(false); });
Modifications.push_back([&Inst]() { Inst.setHasNoUnsignedWrap(true); });
Modifications.push_back([&Inst]() { Inst.setHasNoUnsignedWrap(false); });
@ -244,6 +244,54 @@ void InstModificationIRStrategy::mutate(Instruction &Inst,
break;
}
// Randomly switch operands of instructions
std::pair<int, int> NoneItem({-1, -1}), ShuffleItems(NoneItem);
switch (Inst.getOpcode()) {
case Instruction::SDiv:
case Instruction::UDiv:
case Instruction::SRem:
case Instruction::URem:
case Instruction::FDiv:
case Instruction::FRem: {
// Verify that the after shuffle the second operand is not
// constant 0.
Value *Operand = Inst.getOperand(0);
if (Constant *C = dyn_cast<Constant>(Operand)) {
if (!C->isZeroValue()) {
ShuffleItems = {0, 1};
}
}
break;
}
case Instruction::Select:
ShuffleItems = {1, 2};
break;
case Instruction::Add:
case Instruction::Sub:
case Instruction::Mul:
case Instruction::Shl:
case Instruction::LShr:
case Instruction::AShr:
case Instruction::And:
case Instruction::Or:
case Instruction::Xor:
case Instruction::FAdd:
case Instruction::FSub:
case Instruction::FMul:
case Instruction::ICmp:
case Instruction::FCmp:
case Instruction::ShuffleVector:
ShuffleItems = {0, 1};
break;
}
if (ShuffleItems != NoneItem) {
Modifications.push_back([&Inst, &ShuffleItems]() {
Value *Op0 = Inst.getOperand(ShuffleItems.first);
Inst.setOperand(ShuffleItems.first, Inst.getOperand(ShuffleItems.second));
Inst.setOperand(ShuffleItems.second, Op0);
});
}
auto RS = makeSampler(IB.Rand, Modifications);
if (RS)
RS.getSelection()();

View File

@ -37,24 +37,13 @@ std::unique_ptr<IRMutator> createInjectorMutator() {
return std::make_unique<IRMutator>(std::move(Types), std::move(Strategies));
}
std::unique_ptr<IRMutator> createDeleterMutator() {
template <class Strategy> std::unique_ptr<IRMutator> createMutator() {
std::vector<TypeGetter> Types{
Type::getInt1Ty, Type::getInt8Ty, Type::getInt16Ty, Type::getInt32Ty,
Type::getInt64Ty, Type::getFloatTy, Type::getDoubleTy};
std::vector<std::unique_ptr<IRMutationStrategy>> Strategies;
Strategies.push_back(std::make_unique<InstDeleterIRStrategy>());
return std::make_unique<IRMutator>(std::move(Types), std::move(Strategies));
}
std::unique_ptr<IRMutator> createInstModifierMutator() {
std::vector<TypeGetter> Types{
Type::getInt1Ty, Type::getInt8Ty, Type::getInt16Ty, Type::getInt32Ty,
Type::getInt64Ty, Type::getFloatTy, Type::getDoubleTy};
std::vector<std::unique_ptr<IRMutationStrategy>> Strategies;
Strategies.push_back(std::make_unique<InstModificationIRStrategy>());
Strategies.push_back(std::make_unique<Strategy>());
return std::make_unique<IRMutator>(std::move(Types), std::move(Strategies));
}
@ -113,7 +102,7 @@ TEST(InstDeleterIRStrategyTest, EmptyFunction) {
"ret i32 %L6\n"
"}\n";
auto Mutator = createDeleterMutator();
auto Mutator = createMutator<InstDeleterIRStrategy>();
ASSERT_TRUE(Mutator);
IterateOnSource(Source, *Mutator);
@ -139,7 +128,7 @@ TEST(InstDeleterIRStrategyTest, PhiNodes) {
ret i32 %a.0\n\
}";
auto Mutator = createDeleterMutator();
auto Mutator = createMutator<InstDeleterIRStrategy>();
ASSERT_TRUE(Mutator);
IterateOnSource(Source, *Mutator);
@ -154,7 +143,7 @@ static void checkModifyNoUnsignedAndNoSignedWrap(StringRef Opc) {
ret i32 %a\n\
}");
auto Mutator = createInstModifierMutator();
auto Mutator = createMutator<InstModificationIRStrategy>();
ASSERT_TRUE(Mutator);
auto M = parseAssembly(Source.data(), Ctx);
@ -198,7 +187,7 @@ TEST(InstModificationIRStrategyTest, ICmp) {
ret i1 %a\n\
}";
auto Mutator = createInstModifierMutator();
auto Mutator = createMutator<InstModificationIRStrategy>();
ASSERT_TRUE(Mutator);
auto M = parseAssembly(Source.data(), Ctx);
@ -223,7 +212,7 @@ TEST(InstModificationIRStrategyTest, GEP) {
ret i32* %gep\n\
}";
auto Mutator = createInstModifierMutator();
auto Mutator = createMutator<InstModificationIRStrategy>();
ASSERT_TRUE(Mutator);
auto M = parseAssembly(Source.data(), Ctx);
@ -239,4 +228,83 @@ TEST(InstModificationIRStrategyTest, GEP) {
EXPECT_TRUE(FoundInbounds);
}
/// The caller has to guarantee that function argument are used in the SAME
/// place as the operand.
void VerfyOperandShuffled(StringRef Source, std::pair<int, int> ShuffleItems) {
LLVMContext Ctx;
auto Mutator = createMutator<InstModificationIRStrategy>();
ASSERT_TRUE(Mutator);
auto M = parseAssembly(Source.data(), Ctx);
auto &F = *M->begin();
Instruction *Inst = &*F.begin()->begin();
ASSERT_TRUE(M && !verifyModule(*M, &errs()));
ASSERT_TRUE(Inst->getOperand(ShuffleItems.first) ==
dyn_cast<Value>(F.getArg(ShuffleItems.first)));
ASSERT_TRUE(Inst->getOperand(ShuffleItems.second) ==
dyn_cast<Value>(F.getArg(ShuffleItems.second)));
Mutator->mutateModule(*M, 0, Source.size(), Source.size() + 100);
EXPECT_TRUE(!verifyModule(*M, &errs()));
EXPECT_TRUE(Inst->getOperand(ShuffleItems.first) ==
dyn_cast<Value>(F.getArg(ShuffleItems.second)));
EXPECT_TRUE(Inst->getOperand(ShuffleItems.second) ==
dyn_cast<Value>(F.getArg(ShuffleItems.first)));
}
TEST(InstModificationIRStrategyTest, ShuffleFAdd) {
StringRef Source = "\n\
define float @test(float %0, float %1) {\n\
%add = fadd float %0, %1\n\
ret float %add\n\
}";
VerfyOperandShuffled(Source, {0, 1});
}
TEST(InstModificationIRStrategyTest, ShuffleSelect) {
StringRef Source = "\n\
define float @test(i1 %0, float %1, float %2) {\n\
%select = select i1 %0, float %1, float %2\n\
ret float %select\n\
}";
VerfyOperandShuffled(Source, {1, 2});
}
void VerfyDivDidntShuffle(StringRef Source) {
LLVMContext Ctx;
auto Mutator = createMutator<InstModificationIRStrategy>();
ASSERT_TRUE(Mutator);
auto M = parseAssembly(Source.data(), Ctx);
auto &F = *M->begin();
Instruction *Inst = &*F.begin()->begin();
ASSERT_TRUE(M && !verifyModule(*M, &errs()));
EXPECT_TRUE(isa<Constant>(Inst->getOperand(0)));
EXPECT_TRUE(Inst->getOperand(1) == dyn_cast<Value>(F.getArg(0)));
Mutator->mutateModule(*M, Seed, Source.size(), Source.size() + 100);
EXPECT_TRUE(!verifyModule(*M, &errs()));
// Didn't shuffle.
EXPECT_TRUE(isa<Constant>(Inst->getOperand(0)));
EXPECT_TRUE(Inst->getOperand(1) == dyn_cast<Value>(F.getArg(0)));
}
TEST(InstModificationIRStrategyTest, DidntShuffleSDiv) {
StringRef Source = "\n\
define i32 @test(i32 %0) {\n\
%div = sdiv i32 0, %0\n\
ret i32 %div\n\
}";
VerfyDivDidntShuffle(Source);
}
TEST(InstModificationIRStrategyTest, DidntShuffleFRem) {
StringRef Source = "\n\
define <2 x double> @test(<2 x double> %0) {\n\
%div = frem <2 x double> <double 0.0, double 0.0>, %0\n\
ret <2 x double> %div\n\
}";
VerfyDivDidntShuffle(Source);
}
} // namespace