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