xref: /freebsd/contrib/llvm-project/llvm/lib/FuzzMutate/IRMutator.cpp (revision cfd6422a5217410fbd66f7a7a8a64d9d85e61229)
1 //===-- IRMutator.cpp -----------------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
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"
22 
23 using namespace llvm;
24 
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), {},
29                                                    /*isVarArg=*/false),
30                                  GlobalValue::ExternalLinkage, "f", &M);
31   BasicBlock *BB = BasicBlock::Create(Context, "BB", F);
32   ReturnInst::Create(Context, BB);
33 }
34 
35 void IRMutationStrategy::mutate(Module &M, RandomIRBuilder &IB) {
36   if (M.empty())
37     createEmptyFunction(M);
38 
39   auto RS = makeSampler<Function *>(IB.Rand);
40   for (Function &F : M)
41     if (!F.isDeclaration())
42       RS.sample(&F, /*Weight=*/1);
43   mutate(*RS.getSelection(), IB);
44 }
45 
46 void IRMutationStrategy::mutate(Function &F, RandomIRBuilder &IB) {
47   mutate(*makeSampler(IB.Rand, make_pointer_range(F)).getSelection(), IB);
48 }
49 
50 void IRMutationStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
51   mutate(*makeSampler(IB.Rand, make_pointer_range(BB)).getSelection(), IB);
52 }
53 
54 void IRMutator::mutateModule(Module &M, int Seed, size_t CurSize,
55                              size_t MaxSize) {
56   std::vector<Type *> Types;
57   for (const auto &Getter : AllowedTypes)
58     Types.push_back(Getter(M.getContext()));
59   RandomIRBuilder IB(Seed, Types);
60 
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();
66 
67   Strategy->mutate(M, IB);
68 }
69 
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(); });
76   FPM.run(F, FAM);
77 }
78 
79 void InjectorIRStrategy::mutate(Function &F, RandomIRBuilder &IB) {
80   IRMutationStrategy::mutate(F, IB);
81   eliminateDeadCode(F);
82 }
83 
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);
92   return Ops;
93 }
94 
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);
99   };
100   auto RS = makeSampler(IB.Rand, make_filter_range(Operations, OpMatchesPred));
101   if (RS.isEmpty())
102     return None;
103   return *RS;
104 }
105 
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)
111     return;
112 
113   // Choose an insertion point for our new instruction.
114   size_t IP = uniform<size_t>(IB.Rand, 0, Insts.size() - 1);
115 
116   auto InstsBefore = makeArrayRef(Insts).slice(0, IP);
117   auto InstsAfter = makeArrayRef(Insts).slice(IP);
118 
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));
122 
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
127   if (!OpDesc)
128     return;
129 
130   for (const auto &Pred : makeArrayRef(OpDesc->SourcePreds).slice(1))
131     Srcs.push_back(IB.findOrCreateSource(BB, InstsBefore, Srcs, Pred));
132 
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);
136   }
137 }
138 
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.
148   if (Line < 0)
149     return 0;
150   return Line;
151 }
152 
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))
159       continue;
160 
161     RS.sample(&Inst, /*Weight=*/1);
162   }
163   if (RS.isEmpty())
164     return;
165 
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);
170 }
171 
172 void InstDeleterIRStrategy::mutate(Instruction &Inst, RandomIRBuilder &IB) {
173   assert(!Inst.isTerminator() && "Deleting terminators invalidates CFG");
174 
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();
179     return;
180   }
181 
182   // Otherwise we need to find some other value with the right type to keep the
183   // users happy.
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;
189        ++I) {
190     if (Pred.matches({}, &*I))
191       RS.sample(&*I, /*Weight=*/1);
192     InstsBefore.push_back(&*I);
193   }
194   if (!RS)
195     RS.sample(IB.newSource(*BB, InstsBefore, {}, Pred), /*Weight=*/1);
196 
197   Inst.replaceAllUsesWith(RS.getSelection());
198   Inst.eraseFromParent();
199 }
200