xref: /netbsd-src/external/apache2/llvm/dist/llvm/lib/FuzzMutate/RandomIRBuilder.cpp (revision 7330f729ccf0bd976a06f95fad452fe774fc7fd1)
1*7330f729Sjoerg //===-- RandomIRBuilder.cpp -----------------------------------------------===//
2*7330f729Sjoerg //
3*7330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*7330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
5*7330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*7330f729Sjoerg //
7*7330f729Sjoerg //===----------------------------------------------------------------------===//
8*7330f729Sjoerg 
9*7330f729Sjoerg #include "llvm/FuzzMutate/RandomIRBuilder.h"
10*7330f729Sjoerg #include "llvm/ADT/STLExtras.h"
11*7330f729Sjoerg #include "llvm/FuzzMutate/Random.h"
12*7330f729Sjoerg #include "llvm/IR/BasicBlock.h"
13*7330f729Sjoerg #include "llvm/IR/Constants.h"
14*7330f729Sjoerg #include "llvm/IR/Function.h"
15*7330f729Sjoerg #include "llvm/IR/Instructions.h"
16*7330f729Sjoerg #include "llvm/IR/IntrinsicInst.h"
17*7330f729Sjoerg 
18*7330f729Sjoerg using namespace llvm;
19*7330f729Sjoerg using namespace fuzzerop;
20*7330f729Sjoerg 
findOrCreateSource(BasicBlock & BB,ArrayRef<Instruction * > Insts)21*7330f729Sjoerg Value *RandomIRBuilder::findOrCreateSource(BasicBlock &BB,
22*7330f729Sjoerg                                            ArrayRef<Instruction *> Insts) {
23*7330f729Sjoerg   return findOrCreateSource(BB, Insts, {}, anyType());
24*7330f729Sjoerg }
25*7330f729Sjoerg 
findOrCreateSource(BasicBlock & BB,ArrayRef<Instruction * > Insts,ArrayRef<Value * > Srcs,SourcePred Pred)26*7330f729Sjoerg Value *RandomIRBuilder::findOrCreateSource(BasicBlock &BB,
27*7330f729Sjoerg                                            ArrayRef<Instruction *> Insts,
28*7330f729Sjoerg                                            ArrayRef<Value *> Srcs,
29*7330f729Sjoerg                                            SourcePred Pred) {
30*7330f729Sjoerg   auto MatchesPred = [&Srcs, &Pred](Instruction *Inst) {
31*7330f729Sjoerg     return Pred.matches(Srcs, Inst);
32*7330f729Sjoerg   };
33*7330f729Sjoerg   auto RS = makeSampler(Rand, make_filter_range(Insts, MatchesPred));
34*7330f729Sjoerg   // Also consider choosing no source, meaning we want a new one.
35*7330f729Sjoerg   RS.sample(nullptr, /*Weight=*/1);
36*7330f729Sjoerg   if (Instruction *Src = RS.getSelection())
37*7330f729Sjoerg     return Src;
38*7330f729Sjoerg   return newSource(BB, Insts, Srcs, Pred);
39*7330f729Sjoerg }
40*7330f729Sjoerg 
newSource(BasicBlock & BB,ArrayRef<Instruction * > Insts,ArrayRef<Value * > Srcs,SourcePred Pred)41*7330f729Sjoerg Value *RandomIRBuilder::newSource(BasicBlock &BB, ArrayRef<Instruction *> Insts,
42*7330f729Sjoerg                                   ArrayRef<Value *> Srcs, SourcePred Pred) {
43*7330f729Sjoerg   // Generate some constants to choose from.
44*7330f729Sjoerg   auto RS = makeSampler<Value *>(Rand);
45*7330f729Sjoerg   RS.sample(Pred.generate(Srcs, KnownTypes));
46*7330f729Sjoerg 
47*7330f729Sjoerg   // If we can find a pointer to load from, use it half the time.
48*7330f729Sjoerg   Value *Ptr = findPointer(BB, Insts, Srcs, Pred);
49*7330f729Sjoerg   if (Ptr) {
50*7330f729Sjoerg     // Create load from the chosen pointer
51*7330f729Sjoerg     auto IP = BB.getFirstInsertionPt();
52*7330f729Sjoerg     if (auto *I = dyn_cast<Instruction>(Ptr)) {
53*7330f729Sjoerg       IP = ++I->getIterator();
54*7330f729Sjoerg       assert(IP != BB.end() && "guaranteed by the findPointer");
55*7330f729Sjoerg     }
56*7330f729Sjoerg     auto *NewLoad = new LoadInst(
57*7330f729Sjoerg         cast<PointerType>(Ptr->getType())->getElementType(), Ptr, "L", &*IP);
58*7330f729Sjoerg 
59*7330f729Sjoerg     // Only sample this load if it really matches the descriptor
60*7330f729Sjoerg     if (Pred.matches(Srcs, NewLoad))
61*7330f729Sjoerg       RS.sample(NewLoad, RS.totalWeight());
62*7330f729Sjoerg     else
63*7330f729Sjoerg       NewLoad->eraseFromParent();
64*7330f729Sjoerg   }
65*7330f729Sjoerg 
66*7330f729Sjoerg   assert(!RS.isEmpty() && "Failed to generate sources");
67*7330f729Sjoerg   return RS.getSelection();
68*7330f729Sjoerg }
69*7330f729Sjoerg 
isCompatibleReplacement(const Instruction * I,const Use & Operand,const Value * Replacement)70*7330f729Sjoerg static bool isCompatibleReplacement(const Instruction *I, const Use &Operand,
71*7330f729Sjoerg                                     const Value *Replacement) {
72*7330f729Sjoerg   if (Operand->getType() != Replacement->getType())
73*7330f729Sjoerg     return false;
74*7330f729Sjoerg   switch (I->getOpcode()) {
75*7330f729Sjoerg   case Instruction::GetElementPtr:
76*7330f729Sjoerg   case Instruction::ExtractElement:
77*7330f729Sjoerg   case Instruction::ExtractValue:
78*7330f729Sjoerg     // TODO: We could potentially validate these, but for now just leave indices
79*7330f729Sjoerg     // alone.
80*7330f729Sjoerg     if (Operand.getOperandNo() >= 1)
81*7330f729Sjoerg       return false;
82*7330f729Sjoerg     break;
83*7330f729Sjoerg   case Instruction::InsertValue:
84*7330f729Sjoerg   case Instruction::InsertElement:
85*7330f729Sjoerg   case Instruction::ShuffleVector:
86*7330f729Sjoerg     if (Operand.getOperandNo() >= 2)
87*7330f729Sjoerg       return false;
88*7330f729Sjoerg     break;
89*7330f729Sjoerg   default:
90*7330f729Sjoerg     break;
91*7330f729Sjoerg   }
92*7330f729Sjoerg   return true;
93*7330f729Sjoerg }
94*7330f729Sjoerg 
connectToSink(BasicBlock & BB,ArrayRef<Instruction * > Insts,Value * V)95*7330f729Sjoerg void RandomIRBuilder::connectToSink(BasicBlock &BB,
96*7330f729Sjoerg                                     ArrayRef<Instruction *> Insts, Value *V) {
97*7330f729Sjoerg   auto RS = makeSampler<Use *>(Rand);
98*7330f729Sjoerg   for (auto &I : Insts) {
99*7330f729Sjoerg     if (isa<IntrinsicInst>(I))
100*7330f729Sjoerg       // TODO: Replacing operands of intrinsics would be interesting, but
101*7330f729Sjoerg       // there's no easy way to verify that a given replacement is valid given
102*7330f729Sjoerg       // that intrinsics can impose arbitrary constraints.
103*7330f729Sjoerg       continue;
104*7330f729Sjoerg     for (Use &U : I->operands())
105*7330f729Sjoerg       if (isCompatibleReplacement(I, U, V))
106*7330f729Sjoerg         RS.sample(&U, 1);
107*7330f729Sjoerg   }
108*7330f729Sjoerg   // Also consider choosing no sink, meaning we want a new one.
109*7330f729Sjoerg   RS.sample(nullptr, /*Weight=*/1);
110*7330f729Sjoerg 
111*7330f729Sjoerg   if (Use *Sink = RS.getSelection()) {
112*7330f729Sjoerg     User *U = Sink->getUser();
113*7330f729Sjoerg     unsigned OpNo = Sink->getOperandNo();
114*7330f729Sjoerg     U->setOperand(OpNo, V);
115*7330f729Sjoerg     return;
116*7330f729Sjoerg   }
117*7330f729Sjoerg   newSink(BB, Insts, V);
118*7330f729Sjoerg }
119*7330f729Sjoerg 
newSink(BasicBlock & BB,ArrayRef<Instruction * > Insts,Value * V)120*7330f729Sjoerg void RandomIRBuilder::newSink(BasicBlock &BB, ArrayRef<Instruction *> Insts,
121*7330f729Sjoerg                               Value *V) {
122*7330f729Sjoerg   Value *Ptr = findPointer(BB, Insts, {V}, matchFirstType());
123*7330f729Sjoerg   if (!Ptr) {
124*7330f729Sjoerg     if (uniform(Rand, 0, 1))
125*7330f729Sjoerg       Ptr = new AllocaInst(V->getType(), 0, "A", &*BB.getFirstInsertionPt());
126*7330f729Sjoerg     else
127*7330f729Sjoerg       Ptr = UndefValue::get(PointerType::get(V->getType(), 0));
128*7330f729Sjoerg   }
129*7330f729Sjoerg 
130*7330f729Sjoerg   new StoreInst(V, Ptr, Insts.back());
131*7330f729Sjoerg }
132*7330f729Sjoerg 
findPointer(BasicBlock & BB,ArrayRef<Instruction * > Insts,ArrayRef<Value * > Srcs,SourcePred Pred)133*7330f729Sjoerg Value *RandomIRBuilder::findPointer(BasicBlock &BB,
134*7330f729Sjoerg                                     ArrayRef<Instruction *> Insts,
135*7330f729Sjoerg                                     ArrayRef<Value *> Srcs, SourcePred Pred) {
136*7330f729Sjoerg   auto IsMatchingPtr = [&Srcs, &Pred](Instruction *Inst) {
137*7330f729Sjoerg     // Invoke instructions sometimes produce valid pointers but currently
138*7330f729Sjoerg     // we can't insert loads or stores from them
139*7330f729Sjoerg     if (Inst->isTerminator())
140*7330f729Sjoerg       return false;
141*7330f729Sjoerg 
142*7330f729Sjoerg     if (auto PtrTy = dyn_cast<PointerType>(Inst->getType())) {
143*7330f729Sjoerg       // We can never generate loads from non first class or non sized types
144*7330f729Sjoerg       if (!PtrTy->getElementType()->isSized() ||
145*7330f729Sjoerg           !PtrTy->getElementType()->isFirstClassType())
146*7330f729Sjoerg         return false;
147*7330f729Sjoerg 
148*7330f729Sjoerg       // TODO: Check if this is horribly expensive.
149*7330f729Sjoerg       return Pred.matches(Srcs, UndefValue::get(PtrTy->getElementType()));
150*7330f729Sjoerg     }
151*7330f729Sjoerg     return false;
152*7330f729Sjoerg   };
153*7330f729Sjoerg   if (auto RS = makeSampler(Rand, make_filter_range(Insts, IsMatchingPtr)))
154*7330f729Sjoerg     return RS.getSelection();
155*7330f729Sjoerg   return nullptr;
156*7330f729Sjoerg }
157