xref: /llvm-project/llvm/include/llvm/FuzzMutate/OpDescriptor.h (revision d7c14c8f976fd291984e0c7eed75dd3331b1ed6d)
1 //===-- OpDescriptor.h ------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Provides the fuzzerop::Descriptor class and related tools for describing
10 // operations an IR fuzzer can work with.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_FUZZMUTATE_OPDESCRIPTOR_H
15 #define LLVM_FUZZMUTATE_OPDESCRIPTOR_H
16 
17 #include "llvm/ADT/ArrayRef.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/IR/Constants.h"
20 #include "llvm/IR/DerivedTypes.h"
21 #include "llvm/IR/InstrTypes.h"
22 #include "llvm/IR/Type.h"
23 #include "llvm/IR/Value.h"
24 #include <functional>
25 
26 namespace llvm {
27 class Instruction;
28 namespace fuzzerop {
29 
30 /// @{
31 /// Populate a small list of potentially interesting constants of a given type.
32 void makeConstantsWithType(Type *T, std::vector<Constant *> &Cs);
33 std::vector<Constant *> makeConstantsWithType(Type *T);
34 /// @}
35 
36 /// A matcher/generator for finding suitable values for the next source in an
37 /// operation's partially completed argument list.
38 ///
39 /// Given that we're building some operation X and may have already filled some
40 /// subset of its operands, this predicate determines if some value New is
41 /// suitable for the next operand or generates a set of values that are
42 /// suitable.
43 class SourcePred {
44 public:
45   /// Given a list of already selected operands, returns whether a given new
46   /// operand is suitable for the next operand.
47   using PredT = std::function<bool(ArrayRef<Value *> Cur, const Value *New)>;
48   /// Given a list of already selected operands and a set of valid base types
49   /// for a fuzzer, generates a list of constants that could be used for the
50   /// next operand.
51   using MakeT = std::function<std::vector<Constant *>(
52       ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes)>;
53 
54 private:
55   PredT Pred;
56   MakeT Make;
57 
58 public:
59   /// Create a fully general source predicate.
60   SourcePred(PredT Pred, MakeT Make) : Pred(Pred), Make(Make) {}
61   SourcePred(PredT Pred, std::nullopt_t) : Pred(Pred) {
62     Make = [Pred](ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes) {
63       // Default filter just calls Pred on each of the base types.
64       std::vector<Constant *> Result;
65       for (Type *T : BaseTypes) {
66         Constant *V = PoisonValue::get(T);
67         if (Pred(Cur, V))
68           makeConstantsWithType(T, Result);
69       }
70       if (Result.empty())
71         report_fatal_error("Predicate does not match for base types");
72       return Result;
73     };
74   }
75 
76   /// Returns true if \c New is compatible for the argument after \c Cur
77   bool matches(ArrayRef<Value *> Cur, const Value *New) {
78     return Pred(Cur, New);
79   }
80 
81   /// Generates a list of potential values for the argument after \c Cur.
82   std::vector<Constant *> generate(ArrayRef<Value *> Cur,
83                                    ArrayRef<Type *> BaseTypes) {
84     return Make(Cur, BaseTypes);
85   }
86 };
87 
88 /// A description of some operation we can build while fuzzing IR.
89 struct OpDescriptor {
90   unsigned Weight;
91   SmallVector<SourcePred, 2> SourcePreds;
92   std::function<Value *(ArrayRef<Value *>, BasicBlock::iterator)> BuilderFunc;
93 };
94 
95 static inline SourcePred onlyType(Type *Only) {
96   auto Pred = [Only](ArrayRef<Value *>, const Value *V) {
97     return V->getType() == Only;
98   };
99   auto Make = [Only](ArrayRef<Value *>, ArrayRef<Type *>) {
100     return makeConstantsWithType(Only);
101   };
102   return {Pred, Make};
103 }
104 
105 static inline SourcePred anyType() {
106   auto Pred = [](ArrayRef<Value *>, const Value *V) {
107     return !V->getType()->isVoidTy();
108   };
109   auto Make = std::nullopt;
110   return {Pred, Make};
111 }
112 
113 static inline SourcePred anyIntType() {
114   auto Pred = [](ArrayRef<Value *>, const Value *V) {
115     return V->getType()->isIntegerTy();
116   };
117   auto Make = std::nullopt;
118   return {Pred, Make};
119 }
120 
121 static inline SourcePred anyIntOrVecIntType() {
122   auto Pred = [](ArrayRef<Value *>, const Value *V) {
123     return V->getType()->isIntOrIntVectorTy();
124   };
125   return {Pred, std::nullopt};
126 }
127 
128 static inline SourcePred boolOrVecBoolType() {
129   auto Pred = [](ArrayRef<Value *>, const Value *V) {
130     return V->getType()->isIntOrIntVectorTy(1);
131   };
132   return {Pred, std::nullopt};
133 }
134 
135 static inline SourcePred anyFloatType() {
136   auto Pred = [](ArrayRef<Value *>, const Value *V) {
137     return V->getType()->isFloatingPointTy();
138   };
139   auto Make = std::nullopt;
140   return {Pred, Make};
141 }
142 
143 static inline SourcePred anyFloatOrVecFloatType() {
144   auto Pred = [](ArrayRef<Value *>, const Value *V) {
145     return V->getType()->isFPOrFPVectorTy();
146   };
147   return {Pred, std::nullopt};
148 }
149 
150 static inline SourcePred anyPtrType() {
151   auto Pred = [](ArrayRef<Value *>, const Value *V) {
152     return V->getType()->isPointerTy() && !V->isSwiftError();
153   };
154   auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) {
155     std::vector<Constant *> Result;
156     // TODO: Should these point at something?
157     for (Type *T : Ts)
158       Result.push_back(
159           PoisonValue::get(PointerType::getUnqual(T->getContext())));
160     return Result;
161   };
162   return {Pred, Make};
163 }
164 
165 static inline SourcePred sizedPtrType() {
166   auto Pred = [](ArrayRef<Value *>, const Value *V) {
167     if (V->isSwiftError())
168       return false;
169 
170     return V->getType()->isPointerTy();
171   };
172   auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) {
173     std::vector<Constant *> Result;
174 
175     // TODO: This doesn't really make sense with opaque pointers,
176     // as the pointer type will always be the same.
177     for (Type *T : Ts)
178       if (T->isSized())
179         Result.push_back(
180             PoisonValue::get(PointerType::getUnqual(T->getContext())));
181 
182     return Result;
183   };
184   return {Pred, Make};
185 }
186 
187 static inline SourcePred matchFirstLengthWAnyType() {
188   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
189     assert(!Cur.empty() && "No first source yet");
190     Type *This = V->getType(), *First = Cur[0]->getType();
191     VectorType *ThisVec = dyn_cast<VectorType>(This);
192     VectorType *FirstVec = dyn_cast<VectorType>(First);
193     if (ThisVec && FirstVec) {
194       return ThisVec->getElementCount() == FirstVec->getElementCount();
195     }
196     return (ThisVec == nullptr) && (FirstVec == nullptr) && (!This->isVoidTy());
197   };
198   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes) {
199     assert(!Cur.empty() && "No first source yet");
200     std::vector<Constant *> Result;
201     ElementCount EC;
202     bool isVec = false;
203     if (VectorType *VecTy = dyn_cast<VectorType>(Cur[0]->getType())) {
204       EC = VecTy->getElementCount();
205       isVec = true;
206     }
207     for (Type *T : BaseTypes) {
208       if (VectorType::isValidElementType(T)) {
209         if (isVec)
210           // If the first pred is <i1 x N>, make the result <T x N>
211           makeConstantsWithType(VectorType::get(T, EC), Result);
212         else
213           makeConstantsWithType(T, Result);
214       }
215     }
216     assert(!Result.empty() && "No potential constants.");
217     return Result;
218   };
219   return {Pred, Make};
220 }
221 
222 /// Match values that have the same type as the first source.
223 static inline SourcePred matchSecondType() {
224   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
225     assert((Cur.size() > 1) && "No second source yet");
226     return V->getType() == Cur[1]->getType();
227   };
228   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
229     assert((Cur.size() > 1) && "No second source yet");
230     return makeConstantsWithType(Cur[1]->getType());
231   };
232   return {Pred, Make};
233 }
234 
235 static inline SourcePred anyAggregateType() {
236   auto Pred = [](ArrayRef<Value *>, const Value *V) {
237     // We can't index zero sized arrays.
238     if (isa<ArrayType>(V->getType()))
239       return V->getType()->getArrayNumElements() > 0;
240 
241     // Structs can also be zero sized. I.e opaque types.
242     if (isa<StructType>(V->getType()))
243       return V->getType()->getStructNumElements() > 0;
244 
245     return V->getType()->isAggregateType();
246   };
247   // TODO: For now we only find aggregates in BaseTypes. It might be better to
248   // manufacture them out of the base types in some cases.
249   auto Find = std::nullopt;
250   return {Pred, Find};
251 }
252 
253 static inline SourcePred anyVectorType() {
254   auto Pred = [](ArrayRef<Value *>, const Value *V) {
255     return V->getType()->isVectorTy();
256   };
257   // TODO: For now we only find vectors in BaseTypes. It might be better to
258   // manufacture vectors out of the base types, but it's tricky to be sure
259   // that's actually a reasonable type.
260   auto Make = std::nullopt;
261   return {Pred, Make};
262 }
263 
264 /// Match values that have the same type as the first source.
265 static inline SourcePred matchFirstType() {
266   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
267     assert(!Cur.empty() && "No first source yet");
268     return V->getType() == Cur[0]->getType();
269   };
270   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
271     assert(!Cur.empty() && "No first source yet");
272     return makeConstantsWithType(Cur[0]->getType());
273   };
274   return {Pred, Make};
275 }
276 
277 /// Match values that have the first source's scalar type.
278 static inline SourcePred matchScalarOfFirstType() {
279   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
280     assert(!Cur.empty() && "No first source yet");
281     return V->getType() == Cur[0]->getType()->getScalarType();
282   };
283   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
284     assert(!Cur.empty() && "No first source yet");
285     return makeConstantsWithType(Cur[0]->getType()->getScalarType());
286   };
287   return {Pred, Make};
288 }
289 
290 } // namespace fuzzerop
291 } // namespace llvm
292 
293 #endif // LLVM_FUZZMUTATE_OPDESCRIPTOR_H
294