1 //===-- IRMutator.cpp -----------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/FuzzMutate/IRMutator.h"
10 #include "llvm/ADT/Optional.h"
11 #include "llvm/Analysis/TargetLibraryInfo.h"
12 #include "llvm/FuzzMutate/Operations.h"
13 #include "llvm/FuzzMutate/Random.h"
14 #include "llvm/FuzzMutate/RandomIRBuilder.h"
15 #include "llvm/IR/BasicBlock.h"
16 #include "llvm/IR/Function.h"
17 #include "llvm/IR/InstIterator.h"
18 #include "llvm/IR/Instructions.h"
19 #include "llvm/IR/Module.h"
20 #include "llvm/Support/Debug.h"
21 #include "llvm/Transforms/Scalar/DCE.h"
25 static void createEmptyFunction(Module
&M
) {
26 // TODO: Some arguments and a return value would probably be more interesting.
27 LLVMContext
&Context
= M
.getContext();
28 Function
*F
= Function::Create(FunctionType::get(Type::getVoidTy(Context
), {},
30 GlobalValue::ExternalLinkage
, "f", &M
);
31 BasicBlock
*BB
= BasicBlock::Create(Context
, "BB", F
);
32 ReturnInst::Create(Context
, BB
);
35 void IRMutationStrategy::mutate(Module
&M
, RandomIRBuilder
&IB
) {
37 createEmptyFunction(M
);
39 auto RS
= makeSampler
<Function
*>(IB
.Rand
);
41 if (!F
.isDeclaration())
42 RS
.sample(&F
, /*Weight=*/1);
43 mutate(*RS
.getSelection(), IB
);
46 void IRMutationStrategy::mutate(Function
&F
, RandomIRBuilder
&IB
) {
47 mutate(*makeSampler(IB
.Rand
, make_pointer_range(F
)).getSelection(), IB
);
50 void IRMutationStrategy::mutate(BasicBlock
&BB
, RandomIRBuilder
&IB
) {
51 mutate(*makeSampler(IB
.Rand
, make_pointer_range(BB
)).getSelection(), IB
);
54 void IRMutator::mutateModule(Module
&M
, int Seed
, size_t CurSize
,
56 std::vector
<Type
*> Types
;
57 for (const auto &Getter
: AllowedTypes
)
58 Types
.push_back(Getter(M
.getContext()));
59 RandomIRBuilder
IB(Seed
, Types
);
61 auto RS
= makeSampler
<IRMutationStrategy
*>(IB
.Rand
);
62 for (const auto &Strategy
: Strategies
)
63 RS
.sample(Strategy
.get(),
64 Strategy
->getWeight(CurSize
, MaxSize
, RS
.totalWeight()));
65 auto Strategy
= RS
.getSelection();
67 Strategy
->mutate(M
, IB
);
70 static void eliminateDeadCode(Function
&F
) {
71 FunctionPassManager FPM
;
72 FPM
.addPass(DCEPass());
73 FunctionAnalysisManager FAM
;
74 FAM
.registerPass([&] { return TargetLibraryAnalysis(); });
75 FAM
.registerPass([&] { return PassInstrumentationAnalysis(); });
79 void InjectorIRStrategy::mutate(Function
&F
, RandomIRBuilder
&IB
) {
80 IRMutationStrategy::mutate(F
, IB
);
84 std::vector
<fuzzerop::OpDescriptor
> InjectorIRStrategy::getDefaultOps() {
85 std::vector
<fuzzerop::OpDescriptor
> Ops
;
86 describeFuzzerIntOps(Ops
);
87 describeFuzzerFloatOps(Ops
);
88 describeFuzzerControlFlowOps(Ops
);
89 describeFuzzerPointerOps(Ops
);
90 describeFuzzerAggregateOps(Ops
);
91 describeFuzzerVectorOps(Ops
);
95 Optional
<fuzzerop::OpDescriptor
>
96 InjectorIRStrategy::chooseOperation(Value
*Src
, RandomIRBuilder
&IB
) {
97 auto OpMatchesPred
= [&Src
](fuzzerop::OpDescriptor
&Op
) {
98 return Op
.SourcePreds
[0].matches({}, Src
);
100 auto RS
= makeSampler(IB
.Rand
, make_filter_range(Operations
, OpMatchesPred
));
106 void InjectorIRStrategy::mutate(BasicBlock
&BB
, RandomIRBuilder
&IB
) {
107 SmallVector
<Instruction
*, 32> Insts
;
108 for (auto I
= BB
.getFirstInsertionPt(), E
= BB
.end(); I
!= E
; ++I
)
109 Insts
.push_back(&*I
);
110 if (Insts
.size() < 1)
113 // Choose an insertion point for our new instruction.
114 size_t IP
= uniform
<size_t>(IB
.Rand
, 0, Insts
.size() - 1);
116 auto InstsBefore
= makeArrayRef(Insts
).slice(0, IP
);
117 auto InstsAfter
= makeArrayRef(Insts
).slice(IP
);
119 // Choose a source, which will be used to constrain the operation selection.
120 SmallVector
<Value
*, 2> Srcs
;
121 Srcs
.push_back(IB
.findOrCreateSource(BB
, InstsBefore
));
123 // Choose an operation that's constrained to be valid for the type of the
124 // source, collect any other sources it needs, and then build it.
125 auto OpDesc
= chooseOperation(Srcs
[0], IB
);
126 // Bail if no operation was found
130 for (const auto &Pred
: makeArrayRef(OpDesc
->SourcePreds
).slice(1))
131 Srcs
.push_back(IB
.findOrCreateSource(BB
, InstsBefore
, Srcs
, Pred
));
133 if (Value
*Op
= OpDesc
->BuilderFunc(Srcs
, Insts
[IP
])) {
134 // Find a sink and wire up the results of the operation.
135 IB
.connectToSink(BB
, InstsAfter
, Op
);
139 uint64_t InstDeleterIRStrategy::getWeight(size_t CurrentSize
, size_t MaxSize
,
140 uint64_t CurrentWeight
) {
141 // If we have less than 200 bytes, panic and try to always delete.
142 if (CurrentSize
> MaxSize
- 200)
143 return CurrentWeight
? CurrentWeight
* 100 : 1;
144 // Draw a line starting from when we only have 1k left and increasing linearly
145 // to double the current weight.
146 int Line
= (-2 * CurrentWeight
) * (MaxSize
- CurrentSize
+ 1000);
147 // Clamp negative weights to zero.
153 void InstDeleterIRStrategy::mutate(Function
&F
, RandomIRBuilder
&IB
) {
154 auto RS
= makeSampler
<Instruction
*>(IB
.Rand
);
155 for (Instruction
&Inst
: instructions(F
)) {
156 // TODO: We can't handle these instructions.
157 if (Inst
.isTerminator() || Inst
.isEHPad() ||
158 Inst
.isSwiftError() || isa
<PHINode
>(Inst
))
161 RS
.sample(&Inst
, /*Weight=*/1);
166 // Delete the instruction.
167 mutate(*RS
.getSelection(), IB
);
168 // Clean up any dead code that's left over after removing the instruction.
169 eliminateDeadCode(F
);
172 void InstDeleterIRStrategy::mutate(Instruction
&Inst
, RandomIRBuilder
&IB
) {
173 assert(!Inst
.isTerminator() && "Deleting terminators invalidates CFG");
175 if (Inst
.getType()->isVoidTy()) {
176 // Instructions with void type (ie, store) have no uses to worry about. Just
177 // erase it and move on.
178 Inst
.eraseFromParent();
182 // Otherwise we need to find some other value with the right type to keep the
184 auto Pred
= fuzzerop::onlyType(Inst
.getType());
185 auto RS
= makeSampler
<Value
*>(IB
.Rand
);
186 SmallVector
<Instruction
*, 32> InstsBefore
;
187 BasicBlock
*BB
= Inst
.getParent();
188 for (auto I
= BB
->getFirstInsertionPt(), E
= Inst
.getIterator(); I
!= E
;
190 if (Pred
.matches({}, &*I
))
191 RS
.sample(&*I
, /*Weight=*/1);
192 InstsBefore
.push_back(&*I
);
195 RS
.sample(IB
.newSource(*BB
, InstsBefore
, {}, Pred
), /*Weight=*/1);
197 Inst
.replaceAllUsesWith(RS
.getSelection());
198 Inst
.eraseFromParent();