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