blob: 42e30464b0d4971cff015b5b923b4edf99ca4007 [file] [log] [blame]
Justin Bogner7d449d32017-08-21 22:57:06 +00001//===-- RandomIRBuilder.cpp -----------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "llvm/FuzzMutate/RandomIRBuilder.h"
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/FuzzMutate/Random.h"
13#include "llvm/IR/BasicBlock.h"
14#include "llvm/IR/Constants.h"
15#include "llvm/IR/Function.h"
16#include "llvm/IR/Instructions.h"
17#include "llvm/IR/IntrinsicInst.h"
18#include "llvm/IR/Module.h"
19
20using namespace llvm;
21using namespace fuzzerop;
22
23Value *RandomIRBuilder::findOrCreateSource(BasicBlock &BB,
24 ArrayRef<Instruction *> Insts) {
25 return findOrCreateSource(BB, Insts, {}, anyType());
26}
27
28Value *RandomIRBuilder::findOrCreateSource(BasicBlock &BB,
29 ArrayRef<Instruction *> Insts,
30 ArrayRef<Value *> Srcs,
31 SourcePred Pred) {
32 auto MatchesPred = [&Srcs, &Pred](Instruction *Inst) {
33 return Pred.matches(Srcs, Inst);
34 };
35 auto RS = makeSampler(Rand, make_filter_range(Insts, MatchesPred));
36 // Also consider choosing no source, meaning we want a new one.
37 RS.sample(nullptr, /*Weight=*/1);
38 if (Instruction *Src = RS.getSelection())
39 return Src;
40 return newSource(BB, Insts, Srcs, Pred);
41}
42
43Value *RandomIRBuilder::newSource(BasicBlock &BB, ArrayRef<Instruction *> Insts,
44 ArrayRef<Value *> Srcs, SourcePred Pred) {
45 // Generate some constants to choose from.
46 auto RS = makeSampler<Value *>(Rand);
47 RS.sample(Pred.generate(Srcs, KnownTypes));
48 assert(!RS.isEmpty() && "Failed to generate sources");
49
50 // If we can find a pointer to load from, use it half the time.
51 Value *Ptr = findPointer(BB, Insts, Srcs, Pred);
52 if (Ptr)
53 RS.sample(Ptr, RS.totalWeight());
54
55 Value *Result = RS.getSelection();
56 if (Result != Ptr)
57 return Result;
58
59 // If we choose the pointer, we need to create a load.
60 auto IP = BB.getFirstInsertionPt();
61 if (auto *I = dyn_cast<Instruction>(Ptr))
62 IP = ++I->getIterator();
63 return new LoadInst(Ptr, "L", &*IP);
64}
65
66static bool isCompatibleReplacement(const Instruction *I, const Use &Operand,
67 const Value *Replacement) {
68 if (Operand->getType() != Replacement->getType())
69 return false;
70 switch (I->getOpcode()) {
71 case Instruction::GetElementPtr:
72 case Instruction::ExtractElement:
73 case Instruction::ExtractValue:
74 // TODO: We could potentially validate these, but for now just leave indices
75 // alone.
76 if (Operand.getOperandNo() > 1)
77 return false;
78 break;
79 case Instruction::InsertValue:
80 case Instruction::InsertElement:
81 if (Operand.getOperandNo() > 2)
82 return false;
83 break;
84 default:
85 break;
86 }
87 return true;
88}
89
90void RandomIRBuilder::connectToSink(BasicBlock &BB,
91 ArrayRef<Instruction *> Insts, Value *V) {
92 auto RS = makeSampler<Use *>(Rand);
93 for (auto &I : Insts) {
94 if (isa<IntrinsicInst>(I))
95 // TODO: Replacing operands of intrinsics would be interesting, but
96 // there's no easy way to verify that a given replacement is valid given
97 // that intrinsics can impose arbitrary constraints.
98 continue;
99 for (Use &U : I->operands())
100 if (isCompatibleReplacement(I, U, V))
101 RS.sample(&U, 1);
102 }
103 // Also consider choosing no sink, meaning we want a new one.
104 RS.sample(nullptr, /*Weight=*/1);
105
106 if (Use *Sink = RS.getSelection()) {
107 User *U = Sink->getUser();
108 unsigned OpNo = Sink->getOperandNo();
109 U->setOperand(OpNo, V);
110 return;
111 }
112 newSink(BB, Insts, V);
113}
114
115void RandomIRBuilder::newSink(BasicBlock &BB, ArrayRef<Instruction *> Insts,
116 Value *V) {
117 Value *Ptr = findPointer(BB, Insts, {V}, matchFirstType());
118 if (!Ptr) {
119 if (uniform(Rand, 0, 1))
120 Ptr = new AllocaInst(V->getType(), 0, "A", &*BB.getFirstInsertionPt());
121 else
122 Ptr = UndefValue::get(PointerType::get(V->getType(), 0));
123 }
124
125 new StoreInst(V, Ptr, Insts.back());
126}
127
128Value *RandomIRBuilder::findPointer(BasicBlock &BB,
129 ArrayRef<Instruction *> Insts,
130 ArrayRef<Value *> Srcs, SourcePred Pred) {
131 auto IsMatchingPtr = [&Srcs, &Pred](Instruction *Inst) {
132 if (auto PtrTy = dyn_cast<PointerType>(Inst->getType()))
133 // TODO: Check if this is horribly expensive.
134 return Pred.matches(Srcs, UndefValue::get(PtrTy->getElementType()));
135 return false;
136 };
137 if (auto RS = makeSampler(Rand, make_filter_range(Insts, IsMatchingPtr)))
138 return RS.getSelection();
139 return nullptr;
140}