blob: dd30fda99bea23ed5d2eeb554ac6ad11cb67b9c4 [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===-- OpDescriptor.h ------------------------------------------*- C++ -*-===//
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// Provides the fuzzerop::Descriptor class and related tools for describing
11// operations an IR fuzzer can work with.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_FUZZMUTATE_OPDESCRIPTOR_H
16#define LLVM_FUZZMUTATE_OPDESCRIPTOR_H
17
18#include "llvm/ADT/ArrayRef.h"
19#include "llvm/ADT/STLExtras.h"
20#include "llvm/ADT/SmallVector.h"
21#include "llvm/IR/Constants.h"
22#include "llvm/IR/DerivedTypes.h"
23#include "llvm/IR/Instructions.h"
24#include "llvm/IR/Type.h"
25#include "llvm/IR/Value.h"
26#include <functional>
27
28namespace llvm {
29namespace fuzzerop {
30
31/// @{
32/// Populate a small list of potentially interesting constants of a given type.
33void makeConstantsWithType(Type *T, std::vector<Constant *> &Cs);
34std::vector<Constant *> makeConstantsWithType(Type *T);
35/// @}
36
37/// A matcher/generator for finding suitable values for the next source in an
38/// operation's partially completed argument list.
39///
40/// Given that we're building some operation X and may have already filled some
41/// subset of its operands, this predicate determines if some value New is
42/// suitable for the next operand or generates a set of values that are
43/// suitable.
44class SourcePred {
45public:
46 /// Given a list of already selected operands, returns whether a given new
47 /// operand is suitable for the next operand.
48 using PredT = std::function<bool(ArrayRef<Value *> Cur, const Value *New)>;
49 /// Given a list of already selected operands and a set of valid base types
50 /// for a fuzzer, generates a list of constants that could be used for the
51 /// next operand.
52 using MakeT = std::function<std::vector<Constant *>(
53 ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes)>;
54
55private:
56 PredT Pred;
57 MakeT Make;
58
59public:
60 /// Create a fully general source predicate.
61 SourcePred(PredT Pred, MakeT Make) : Pred(Pred), Make(Make) {}
62 SourcePred(PredT Pred, NoneType) : Pred(Pred) {
63 Make = [Pred](ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes) {
64 // Default filter just calls Pred on each of the base types.
65 std::vector<Constant *> Result;
66 for (Type *T : BaseTypes) {
67 Constant *V = UndefValue::get(T);
68 if (Pred(Cur, V))
69 makeConstantsWithType(T, Result);
70 }
71 if (Result.empty())
72 report_fatal_error("Predicate does not match for base types");
73 return Result;
74 };
75 }
76
77 /// Returns true if \c New is compatible for the argument after \c Cur
78 bool matches(ArrayRef<Value *> Cur, const Value *New) {
79 return Pred(Cur, New);
80 }
81
82 /// Generates a list of potential values for the argument after \c Cur.
83 std::vector<Constant *> generate(ArrayRef<Value *> Cur,
84 ArrayRef<Type *> BaseTypes) {
85 return Make(Cur, BaseTypes);
86 }
87};
88
89/// A description of some operation we can build while fuzzing IR.
90struct OpDescriptor {
91 unsigned Weight;
92 SmallVector<SourcePred, 2> SourcePreds;
93 std::function<Value *(ArrayRef<Value *>, Instruction *)> BuilderFunc;
94};
95
96static inline SourcePred onlyType(Type *Only) {
97 auto Pred = [Only](ArrayRef<Value *>, const Value *V) {
98 return V->getType() == Only;
99 };
100 auto Make = [Only](ArrayRef<Value *>, ArrayRef<Type *>) {
101 return makeConstantsWithType(Only);
102 };
103 return {Pred, Make};
104}
105
106static inline SourcePred anyType() {
107 auto Pred = [](ArrayRef<Value *>, const Value *V) {
108 return !V->getType()->isVoidTy();
109 };
110 auto Make = None;
111 return {Pred, Make};
112}
113
114static inline SourcePred anyIntType() {
115 auto Pred = [](ArrayRef<Value *>, const Value *V) {
116 return V->getType()->isIntegerTy();
117 };
118 auto Make = None;
119 return {Pred, Make};
120}
121
122static inline SourcePred anyFloatType() {
123 auto Pred = [](ArrayRef<Value *>, const Value *V) {
124 return V->getType()->isFloatingPointTy();
125 };
126 auto Make = None;
127 return {Pred, Make};
128}
129
130static inline SourcePred anyPtrType() {
131 auto Pred = [](ArrayRef<Value *>, const Value *V) {
132 return V->getType()->isPointerTy() && !V->isSwiftError();
133 };
134 auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) {
135 std::vector<Constant *> Result;
136 // TODO: Should these point at something?
137 for (Type *T : Ts)
138 Result.push_back(UndefValue::get(PointerType::getUnqual(T)));
139 return Result;
140 };
141 return {Pred, Make};
142}
143
144static inline SourcePred sizedPtrType() {
145 auto Pred = [](ArrayRef<Value *>, const Value *V) {
146 if (V->isSwiftError())
147 return false;
148
149 if (const auto *PtrT = dyn_cast<PointerType>(V->getType()))
150 return PtrT->getElementType()->isSized();
151 return false;
152 };
153 auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) {
154 std::vector<Constant *> Result;
155
156 for (Type *T : Ts)
157 if (T->isSized())
158 Result.push_back(UndefValue::get(PointerType::getUnqual(T)));
159
160 return Result;
161 };
162 return {Pred, Make};
163}
164
165static inline SourcePred anyAggregateType() {
166 auto Pred = [](ArrayRef<Value *>, const Value *V) {
167 // We can't index zero sized arrays.
168 if (isa<ArrayType>(V->getType()))
169 return V->getType()->getArrayNumElements() > 0;
170
171 // Structs can also be zero sized. I.e opaque types.
172 if (isa<StructType>(V->getType()))
173 return V->getType()->getStructNumElements() > 0;
174
175 return V->getType()->isAggregateType();
176 };
177 // TODO: For now we only find aggregates in BaseTypes. It might be better to
178 // manufacture them out of the base types in some cases.
179 auto Find = None;
180 return {Pred, Find};
181}
182
183static inline SourcePred anyVectorType() {
184 auto Pred = [](ArrayRef<Value *>, const Value *V) {
185 return V->getType()->isVectorTy();
186 };
187 // TODO: For now we only find vectors in BaseTypes. It might be better to
188 // manufacture vectors out of the base types, but it's tricky to be sure
189 // that's actually a reasonable type.
190 auto Make = None;
191 return {Pred, Make};
192}
193
194/// Match values that have the same type as the first source.
195static inline SourcePred matchFirstType() {
196 auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
197 assert(!Cur.empty() && "No first source yet");
198 return V->getType() == Cur[0]->getType();
199 };
200 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
201 assert(!Cur.empty() && "No first source yet");
202 return makeConstantsWithType(Cur[0]->getType());
203 };
204 return {Pred, Make};
205}
206
207/// Match values that have the first source's scalar type.
208static inline SourcePred matchScalarOfFirstType() {
209 auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
210 assert(!Cur.empty() && "No first source yet");
211 return V->getType() == Cur[0]->getType()->getScalarType();
212 };
213 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
214 assert(!Cur.empty() && "No first source yet");
215 return makeConstantsWithType(Cur[0]->getType()->getScalarType());
216 };
217 return {Pred, Make};
218}
219
220} // end fuzzerop namespace
221} // end llvm namespace
222
223#endif // LLVM_FUZZMUTATE_OPDESCRIPTOR_H