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