mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 02:33:06 +01:00
[FuzzMutate] Add mutator to modify instruction flags.
This patch adds a new InstModificationIRStrategy to mutate flags/options for instructions. For example, it may add or remove nuw/nsw flags from add, mul, sub, shl instructions or change the predicate for icmp instructions. Subtle changes such as those mentioned above should lead to a more interesting range of inputs. The presence or absence of overflow flags can expose subtle bugs, for example. Reviewed By: bogner Differential Revision: https://reviews.llvm.org/D94905
This commit is contained in:
parent
dcbeaf027c
commit
5b8c530938
@ -102,6 +102,17 @@ public:
|
|||||||
void mutate(Instruction &Inst, RandomIRBuilder &IB) override;
|
void mutate(Instruction &Inst, RandomIRBuilder &IB) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class InstModificationIRStrategy : public IRMutationStrategy {
|
||||||
|
public:
|
||||||
|
uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
|
||||||
|
uint64_t CurrentWeight) override {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
using IRMutationStrategy::mutate;
|
||||||
|
void mutate(Instruction &Inst, RandomIRBuilder &IB) override;
|
||||||
|
};
|
||||||
|
|
||||||
} // end llvm namespace
|
} // end llvm namespace
|
||||||
|
|
||||||
#endif // LLVM_FUZZMUTATE_IRMUTATOR_H
|
#endif // LLVM_FUZZMUTATE_IRMUTATOR_H
|
||||||
|
@ -197,3 +197,46 @@ void InstDeleterIRStrategy::mutate(Instruction &Inst, RandomIRBuilder &IB) {
|
|||||||
Inst.replaceAllUsesWith(RS.getSelection());
|
Inst.replaceAllUsesWith(RS.getSelection());
|
||||||
Inst.eraseFromParent();
|
Inst.eraseFromParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InstModificationIRStrategy::mutate(Instruction &Inst,
|
||||||
|
RandomIRBuilder &IB) {
|
||||||
|
SmallVector<std::function<void()>, 8> Modifications;
|
||||||
|
CmpInst *CI = nullptr;
|
||||||
|
GetElementPtrInst *GEP = nullptr;
|
||||||
|
switch (Inst.getOpcode()) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case Instruction::Add:
|
||||||
|
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.setHasNoUnsignedWrap(true); });
|
||||||
|
Modifications.push_back([&Inst]() { Inst.setHasNoUnsignedWrap(false); });
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Instruction::ICmp:
|
||||||
|
CI = cast<ICmpInst>(&Inst);
|
||||||
|
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_EQ); });
|
||||||
|
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_NE); });
|
||||||
|
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_UGT); });
|
||||||
|
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_UGE); });
|
||||||
|
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_ULT); });
|
||||||
|
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_ULE); });
|
||||||
|
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_SGT); });
|
||||||
|
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_SGE); });
|
||||||
|
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_SLT); });
|
||||||
|
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_SLE); });
|
||||||
|
break;
|
||||||
|
case Instruction::GetElementPtr:
|
||||||
|
GEP = cast<GetElementPtrInst>(&Inst);
|
||||||
|
Modifications.push_back([GEP]() { GEP->setIsInBounds(true); });
|
||||||
|
Modifications.push_back([GEP]() { GEP->setIsInBounds(false); });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto RS = makeSampler(IB.Rand, Modifications);
|
||||||
|
if (RS)
|
||||||
|
RS.getSelection()();
|
||||||
|
}
|
||||||
|
@ -51,6 +51,7 @@ std::unique_ptr<IRMutator> createOptMutator() {
|
|||||||
InjectorIRStrategy::getDefaultOps()));
|
InjectorIRStrategy::getDefaultOps()));
|
||||||
Strategies.push_back(
|
Strategies.push_back(
|
||||||
std::make_unique<InstDeleterIRStrategy>());
|
std::make_unique<InstDeleterIRStrategy>());
|
||||||
|
Strategies.push_back(std::make_unique<InstModificationIRStrategy>());
|
||||||
|
|
||||||
return std::make_unique<IRMutator>(std::move(Types), std::move(Strategies));
|
return std::make_unique<IRMutator>(std::move(Types), std::move(Strategies));
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,17 @@ std::unique_ptr<IRMutator> createDeleterMutator() {
|
|||||||
return std::make_unique<IRMutator>(std::move(Types), std::move(Strategies));
|
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>());
|
||||||
|
|
||||||
|
return std::make_unique<IRMutator>(std::move(Types), std::move(Strategies));
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<Module> parseAssembly(
|
std::unique_ptr<Module> parseAssembly(
|
||||||
const char *Assembly, LLVMContext &Context) {
|
const char *Assembly, LLVMContext &Context) {
|
||||||
|
|
||||||
@ -135,4 +146,98 @@ TEST(InstDeleterIRStrategyTest, PhiNodes) {
|
|||||||
IterateOnSource(Source, *Mutator);
|
IterateOnSource(Source, *Mutator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void checkModifyNoUnsignedAndNoSignedWrap(StringRef Opc) {
|
||||||
|
LLVMContext Ctx;
|
||||||
|
std::string Source = std::string("\n\
|
||||||
|
define i32 @test(i32 %x) {\n\
|
||||||
|
%a = ") + Opc.str() +
|
||||||
|
std::string(" i32 %x, 10\n\
|
||||||
|
ret i32 %a\n\
|
||||||
|
}");
|
||||||
|
|
||||||
|
auto Mutator = createInstModifierMutator();
|
||||||
|
ASSERT_TRUE(Mutator);
|
||||||
|
|
||||||
|
auto M = parseAssembly(Source.data(), Ctx);
|
||||||
|
auto &F = *M->begin();
|
||||||
|
auto *AddI = &*F.begin()->begin();
|
||||||
|
ASSERT_TRUE(M && !verifyModule(*M, &errs()));
|
||||||
|
bool FoundNUW = false;
|
||||||
|
bool FoundNSW = false;
|
||||||
|
for (int i = 0; i < 100; ++i) {
|
||||||
|
Mutator->mutateModule(*M, Seed + i, Source.size(), Source.size() + 100);
|
||||||
|
EXPECT_TRUE(!verifyModule(*M, &errs()));
|
||||||
|
FoundNUW |= AddI->hasNoUnsignedWrap();
|
||||||
|
FoundNSW |= AddI->hasNoSignedWrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The mutator should have added nuw and nsw during some mutations.
|
||||||
|
EXPECT_TRUE(FoundNUW);
|
||||||
|
EXPECT_TRUE(FoundNSW);
|
||||||
|
}
|
||||||
|
TEST(InstModificationIRStrategyTest, Add) {
|
||||||
|
checkModifyNoUnsignedAndNoSignedWrap("add");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(InstModificationIRStrategyTest, Sub) {
|
||||||
|
checkModifyNoUnsignedAndNoSignedWrap("sub");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(InstModificationIRStrategyTest, Mul) {
|
||||||
|
checkModifyNoUnsignedAndNoSignedWrap("mul");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(InstModificationIRStrategyTest, Shl) {
|
||||||
|
checkModifyNoUnsignedAndNoSignedWrap("shl");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(InstModificationIRStrategyTest, ICmp) {
|
||||||
|
LLVMContext Ctx;
|
||||||
|
StringRef Source = "\n\
|
||||||
|
define i1 @test(i32 %x) {\n\
|
||||||
|
%a = icmp eq i32 %x, 10\n\
|
||||||
|
ret i1 %a\n\
|
||||||
|
}";
|
||||||
|
|
||||||
|
auto Mutator = createInstModifierMutator();
|
||||||
|
ASSERT_TRUE(Mutator);
|
||||||
|
|
||||||
|
auto M = parseAssembly(Source.data(), Ctx);
|
||||||
|
auto &F = *M->begin();
|
||||||
|
CmpInst *CI = cast<CmpInst>(&*F.begin()->begin());
|
||||||
|
ASSERT_TRUE(M && !verifyModule(*M, &errs()));
|
||||||
|
bool FoundNE = false;
|
||||||
|
for (int i = 0; i < 100; ++i) {
|
||||||
|
Mutator->mutateModule(*M, Seed + i, Source.size(), Source.size() + 100);
|
||||||
|
EXPECT_TRUE(!verifyModule(*M, &errs()));
|
||||||
|
FoundNE |= CI->getPredicate() == CmpInst::ICMP_NE;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_TRUE(FoundNE);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(InstModificationIRStrategyTest, GEP) {
|
||||||
|
LLVMContext Ctx;
|
||||||
|
StringRef Source = "\n\
|
||||||
|
define i32* @test(i32* %ptr) {\n\
|
||||||
|
%gep = getelementptr i32, i32* %ptr, i32 10\n\
|
||||||
|
ret i32* %gep\n\
|
||||||
|
}";
|
||||||
|
|
||||||
|
auto Mutator = createInstModifierMutator();
|
||||||
|
ASSERT_TRUE(Mutator);
|
||||||
|
|
||||||
|
auto M = parseAssembly(Source.data(), Ctx);
|
||||||
|
auto &F = *M->begin();
|
||||||
|
GetElementPtrInst *GEP = cast<GetElementPtrInst>(&*F.begin()->begin());
|
||||||
|
ASSERT_TRUE(M && !verifyModule(*M, &errs()));
|
||||||
|
bool FoundInbounds = false;
|
||||||
|
for (int i = 0; i < 100; ++i) {
|
||||||
|
Mutator->mutateModule(*M, Seed + i, Source.size(), Source.size() + 100);
|
||||||
|
EXPECT_TRUE(!verifyModule(*M, &errs()));
|
||||||
|
FoundInbounds |= GEP->isInBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_TRUE(FoundInbounds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user