Skip to content

Commit 166d40f

Browse files
committed
[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
1 parent 3b9677e commit 166d40f

File tree

4 files changed

+160
-0
lines changed

4 files changed

+160
-0
lines changed

llvm/include/llvm/FuzzMutate/IRMutator.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,17 @@ class InstDeleterIRStrategy : public IRMutationStrategy {
102102
void mutate(Instruction &Inst, RandomIRBuilder &IB) override;
103103
};
104104

105+
class InstModificationIRStrategy : public IRMutationStrategy {
106+
public:
107+
uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
108+
uint64_t CurrentWeight) override {
109+
return 4;
110+
}
111+
112+
using IRMutationStrategy::mutate;
113+
void mutate(Instruction &Inst, RandomIRBuilder &IB) override;
114+
};
115+
105116
} // end llvm namespace
106117

107118
#endif // LLVM_FUZZMUTATE_IRMUTATOR_H

llvm/lib/FuzzMutate/IRMutator.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,46 @@ void InstDeleterIRStrategy::mutate(Instruction &Inst, RandomIRBuilder &IB) {
197197
Inst.replaceAllUsesWith(RS.getSelection());
198198
Inst.eraseFromParent();
199199
}
200+
201+
void InstModificationIRStrategy::mutate(Instruction &Inst,
202+
RandomIRBuilder &IB) {
203+
SmallVector<std::function<void()>, 8> Modifications;
204+
CmpInst *CI = nullptr;
205+
GetElementPtrInst *GEP = nullptr;
206+
switch (Inst.getOpcode()) {
207+
default:
208+
break;
209+
case Instruction::Add:
210+
case Instruction::Mul:
211+
case Instruction::Sub:
212+
case Instruction::Shl:
213+
Modifications.push_back([&Inst]() { Inst.setHasNoSignedWrap(true); }),
214+
Modifications.push_back([&Inst]() { Inst.setHasNoSignedWrap(false); });
215+
Modifications.push_back([&Inst]() { Inst.setHasNoUnsignedWrap(true); });
216+
Modifications.push_back([&Inst]() { Inst.setHasNoUnsignedWrap(false); });
217+
218+
break;
219+
case Instruction::ICmp:
220+
CI = cast<ICmpInst>(&Inst);
221+
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_EQ); });
222+
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_NE); });
223+
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_UGT); });
224+
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_UGE); });
225+
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_ULT); });
226+
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_ULE); });
227+
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_SGT); });
228+
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_SGE); });
229+
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_SLT); });
230+
Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_SLE); });
231+
break;
232+
case Instruction::GetElementPtr:
233+
GEP = cast<GetElementPtrInst>(&Inst);
234+
Modifications.push_back([GEP]() { GEP->setIsInBounds(true); });
235+
Modifications.push_back([GEP]() { GEP->setIsInBounds(false); });
236+
break;
237+
}
238+
239+
auto RS = makeSampler(IB.Rand, Modifications);
240+
if (RS)
241+
RS.getSelection()();
242+
}

llvm/tools/llvm-opt-fuzzer/llvm-opt-fuzzer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ std::unique_ptr<IRMutator> createOptMutator() {
5151
InjectorIRStrategy::getDefaultOps()));
5252
Strategies.push_back(
5353
std::make_unique<InstDeleterIRStrategy>());
54+
Strategies.push_back(std::make_unique<InstModificationIRStrategy>());
5455

5556
return std::make_unique<IRMutator>(std::move(Types), std::move(Strategies));
5657
}

llvm/unittests/FuzzMutate/StrategiesTest.cpp

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@ std::unique_ptr<IRMutator> createDeleterMutator() {
4949
return std::make_unique<IRMutator>(std::move(Types), std::move(Strategies));
5050
}
5151

52+
std::unique_ptr<IRMutator> createInstModifierMutator() {
53+
std::vector<TypeGetter> Types{
54+
Type::getInt1Ty, Type::getInt8Ty, Type::getInt16Ty, Type::getInt32Ty,
55+
Type::getInt64Ty, Type::getFloatTy, Type::getDoubleTy};
56+
57+
std::vector<std::unique_ptr<IRMutationStrategy>> Strategies;
58+
Strategies.push_back(std::make_unique<InstModificationIRStrategy>());
59+
60+
return std::make_unique<IRMutator>(std::move(Types), std::move(Strategies));
61+
}
62+
5263
std::unique_ptr<Module> parseAssembly(
5364
const char *Assembly, LLVMContext &Context) {
5465

@@ -135,4 +146,98 @@ TEST(InstDeleterIRStrategyTest, PhiNodes) {
135146
IterateOnSource(Source, *Mutator);
136147
}
137148

149+
static void checkModifyNoUnsignedAndNoSignedWrap(StringRef Opc) {
150+
LLVMContext Ctx;
151+
std::string Source = std::string("\n\
152+
define i32 @test(i32 %x) {\n\
153+
%a = ") + Opc.str() +
154+
std::string(" i32 %x, 10\n\
155+
ret i32 %a\n\
156+
}");
157+
158+
auto Mutator = createInstModifierMutator();
159+
ASSERT_TRUE(Mutator);
160+
161+
auto M = parseAssembly(Source.data(), Ctx);
162+
auto &F = *M->begin();
163+
auto *AddI = &*F.begin()->begin();
164+
ASSERT_TRUE(M && !verifyModule(*M, &errs()));
165+
bool FoundNUW = false;
166+
bool FoundNSW = false;
167+
for (int i = 0; i < 100; ++i) {
168+
Mutator->mutateModule(*M, Seed + i, Source.size(), Source.size() + 100);
169+
EXPECT_TRUE(!verifyModule(*M, &errs()));
170+
FoundNUW |= AddI->hasNoUnsignedWrap();
171+
FoundNSW |= AddI->hasNoSignedWrap();
172+
}
173+
174+
// The mutator should have added nuw and nsw during some mutations.
175+
EXPECT_TRUE(FoundNUW);
176+
EXPECT_TRUE(FoundNSW);
177+
}
178+
TEST(InstModificationIRStrategyTest, Add) {
179+
checkModifyNoUnsignedAndNoSignedWrap("add");
180+
}
181+
182+
TEST(InstModificationIRStrategyTest, Sub) {
183+
checkModifyNoUnsignedAndNoSignedWrap("sub");
184+
}
185+
186+
TEST(InstModificationIRStrategyTest, Mul) {
187+
checkModifyNoUnsignedAndNoSignedWrap("mul");
188+
}
189+
190+
TEST(InstModificationIRStrategyTest, Shl) {
191+
checkModifyNoUnsignedAndNoSignedWrap("shl");
192+
}
193+
194+
TEST(InstModificationIRStrategyTest, ICmp) {
195+
LLVMContext Ctx;
196+
StringRef Source = "\n\
197+
define i1 @test(i32 %x) {\n\
198+
%a = icmp eq i32 %x, 10\n\
199+
ret i1 %a\n\
200+
}";
201+
202+
auto Mutator = createInstModifierMutator();
203+
ASSERT_TRUE(Mutator);
204+
205+
auto M = parseAssembly(Source.data(), Ctx);
206+
auto &F = *M->begin();
207+
CmpInst *CI = cast<CmpInst>(&*F.begin()->begin());
208+
ASSERT_TRUE(M && !verifyModule(*M, &errs()));
209+
bool FoundNE = false;
210+
for (int i = 0; i < 100; ++i) {
211+
Mutator->mutateModule(*M, Seed + i, Source.size(), Source.size() + 100);
212+
EXPECT_TRUE(!verifyModule(*M, &errs()));
213+
FoundNE |= CI->getPredicate() == CmpInst::ICMP_NE;
214+
}
215+
216+
EXPECT_TRUE(FoundNE);
217+
}
218+
219+
TEST(InstModificationIRStrategyTest, GEP) {
220+
LLVMContext Ctx;
221+
StringRef Source = "\n\
222+
define i32* @test(i32* %ptr) {\n\
223+
%gep = getelementptr i32, i32* %ptr, i32 10\n\
224+
ret i32* %gep\n\
225+
}";
226+
227+
auto Mutator = createInstModifierMutator();
228+
ASSERT_TRUE(Mutator);
229+
230+
auto M = parseAssembly(Source.data(), Ctx);
231+
auto &F = *M->begin();
232+
GetElementPtrInst *GEP = cast<GetElementPtrInst>(&*F.begin()->begin());
233+
ASSERT_TRUE(M && !verifyModule(*M, &errs()));
234+
bool FoundInbounds = false;
235+
for (int i = 0; i < 100; ++i) {
236+
Mutator->mutateModule(*M, Seed + i, Source.size(), Source.size() + 100);
237+
EXPECT_TRUE(!verifyModule(*M, &errs()));
238+
FoundInbounds |= GEP->isInBounds();
239+
}
240+
241+
EXPECT_TRUE(FoundInbounds);
242+
}
138243
}

0 commit comments

Comments
 (0)