• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- 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 
28 namespace llvm {
29 namespace fuzzerop {
30 
31 /// @{
32 /// Populate a small list of potentially interesting constants of a given type.
33 void makeConstantsWithType(Type *T, std::vector<Constant *> &Cs);
34 std::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.
44 class SourcePred {
45 public:
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 
55 private:
56   PredT Pred;
57   MakeT Make;
58 
59 public:
60   /// Create a fully general source predicate.
SourcePred(PredT Pred,MakeT Make)61   SourcePred(PredT Pred, MakeT Make) : Pred(Pred), Make(Make) {}
SourcePred(PredT Pred,NoneType)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
matches(ArrayRef<Value * > Cur,const Value * New)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.
generate(ArrayRef<Value * > Cur,ArrayRef<Type * > BaseTypes)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.
90 struct OpDescriptor {
91   unsigned Weight;
92   SmallVector<SourcePred, 2> SourcePreds;
93   std::function<Value *(ArrayRef<Value *>, Instruction *)> BuilderFunc;
94 };
95 
onlyType(Type * Only)96 static 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 
anyType()106 static 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 
anyIntType()114 static 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 
anyFloatType()122 static 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 
anyPtrType()130 static 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 
sizedPtrType()144 static 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 
anyAggregateType()165 static 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 
anyVectorType()183 static 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.
matchFirstType()195 static 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.
matchScalarOfFirstType()208 static 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
224