blob: 8fe9d0dc85795df217177c89ecdae98fdc47f77d [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));
Justin Bogner7d449d32017-08-21 22:57:06 +000048
49 // If we can find a pointer to load from, use it half the time.
50 Value *Ptr = findPointer(BB, Insts, Srcs, Pred);
Igor Laevskyfaacdf82017-11-30 15:24:41 +000051 if (Ptr) {
52 // Create load from the chosen pointer
53 auto IP = BB.getFirstInsertionPt();
Igor Laevsky76b36d32017-12-08 08:53:16 +000054 if (auto *I = dyn_cast<Instruction>(Ptr)) {
Igor Laevskyfaacdf82017-11-30 15:24:41 +000055 IP = ++I->getIterator();
Igor Laevsky76b36d32017-12-08 08:53:16 +000056 assert(IP != BB.end() && "guaranteed by the findPointer");
57 }
Igor Laevskyfaacdf82017-11-30 15:24:41 +000058 auto *NewLoad = new LoadInst(Ptr, "L", &*IP);
Justin Bogner7d449d32017-08-21 22:57:06 +000059
Igor Laevskyfaacdf82017-11-30 15:24:41 +000060 // Only sample this load if it really matches the descriptor
61 if (Pred.matches(Srcs, NewLoad))
62 RS.sample(NewLoad, RS.totalWeight());
63 else
64 NewLoad->eraseFromParent();
65 }
Justin Bogner7d449d32017-08-21 22:57:06 +000066
Igor Laevskyfaacdf82017-11-30 15:24:41 +000067 assert(!RS.isEmpty() && "Failed to generate sources");
68 return RS.getSelection();
Justin Bogner7d449d32017-08-21 22:57:06 +000069}
70
71static bool isCompatibleReplacement(const Instruction *I, const Use &Operand,
72 const Value *Replacement) {
73 if (Operand->getType() != Replacement->getType())
74 return false;
75 switch (I->getOpcode()) {
76 case Instruction::GetElementPtr:
77 case Instruction::ExtractElement:
78 case Instruction::ExtractValue:
79 // TODO: We could potentially validate these, but for now just leave indices
80 // alone.
Igor Laevsky65902db2017-11-30 15:29:16 +000081 if (Operand.getOperandNo() >= 1)
Justin Bogner7d449d32017-08-21 22:57:06 +000082 return false;
83 break;
84 case Instruction::InsertValue:
85 case Instruction::InsertElement:
Igor Laevsky65902db2017-11-30 15:29:16 +000086 case Instruction::ShuffleVector:
87 if (Operand.getOperandNo() >= 2)
Justin Bogner7d449d32017-08-21 22:57:06 +000088 return false;
89 break;
90 default:
91 break;
92 }
93 return true;
94}
95
96void RandomIRBuilder::connectToSink(BasicBlock &BB,
97 ArrayRef<Instruction *> Insts, Value *V) {
98 auto RS = makeSampler<Use *>(Rand);
99 for (auto &I : Insts) {
100 if (isa<IntrinsicInst>(I))
101 // TODO: Replacing operands of intrinsics would be interesting, but
102 // there's no easy way to verify that a given replacement is valid given
103 // that intrinsics can impose arbitrary constraints.
104 continue;
105 for (Use &U : I->operands())
106 if (isCompatibleReplacement(I, U, V))
107 RS.sample(&U, 1);
108 }
109 // Also consider choosing no sink, meaning we want a new one.
110 RS.sample(nullptr, /*Weight=*/1);
111
112 if (Use *Sink = RS.getSelection()) {
113 User *U = Sink->getUser();
114 unsigned OpNo = Sink->getOperandNo();
115 U->setOperand(OpNo, V);
116 return;
117 }
118 newSink(BB, Insts, V);
119}
120
121void RandomIRBuilder::newSink(BasicBlock &BB, ArrayRef<Instruction *> Insts,
122 Value *V) {
123 Value *Ptr = findPointer(BB, Insts, {V}, matchFirstType());
124 if (!Ptr) {
125 if (uniform(Rand, 0, 1))
126 Ptr = new AllocaInst(V->getType(), 0, "A", &*BB.getFirstInsertionPt());
127 else
128 Ptr = UndefValue::get(PointerType::get(V->getType(), 0));
129 }
130
131 new StoreInst(V, Ptr, Insts.back());
132}
133
134Value *RandomIRBuilder::findPointer(BasicBlock &BB,
135 ArrayRef<Instruction *> Insts,
136 ArrayRef<Value *> Srcs, SourcePred Pred) {
137 auto IsMatchingPtr = [&Srcs, &Pred](Instruction *Inst) {
Igor Laevsky76b36d32017-12-08 08:53:16 +0000138 // Invoke instructions sometimes produce valid pointers but currently
139 // we can't insert loads or stores from them
140 if (isa<TerminatorInst>(Inst))
141 return false;
142
Igor Laevskyd209ff92017-12-13 11:49:04 +0000143 if (auto PtrTy = dyn_cast<PointerType>(Inst->getType())) {
144 // We can never generate loads from non first class or non sized types
145 if (!PtrTy->getElementType()->isSized() ||
146 !PtrTy->getElementType()->isFirstClassType())
147 return false;
148
Justin Bogner7d449d32017-08-21 22:57:06 +0000149 // TODO: Check if this is horribly expensive.
150 return Pred.matches(Srcs, UndefValue::get(PtrTy->getElementType()));
Igor Laevskyd209ff92017-12-13 11:49:04 +0000151 }
Justin Bogner7d449d32017-08-21 22:57:06 +0000152 return false;
153 };
154 if (auto RS = makeSampler(Rand, make_filter_range(Insts, IsMatchingPtr)))
155 return RS.getSelection();
156 return nullptr;
157}