xref: /freebsd/contrib/llvm-project/llvm/include/llvm/FuzzMutate/OpDescriptor.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 "llvm/Support/Compiler.h"
25 #include <functional>
26 
27 namespace llvm {
28 class Instruction;
29 namespace fuzzerop {
30 
31 /// @{
32 /// Populate a small list of potentially interesting constants of a given type.
33 LLVM_ABI void makeConstantsWithType(Type *T, std::vector<Constant *> &Cs);
34 LLVM_ABI 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,std::nullopt_t)62   SourcePred(PredT Pred, std::nullopt_t) : 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 = PoisonValue::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 *>, BasicBlock::iterator)> 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 = std::nullopt;
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 = std::nullopt;
119   return {Pred, Make};
120 }
121 
anyIntOrVecIntType()122 static inline SourcePred anyIntOrVecIntType() {
123   auto Pred = [](ArrayRef<Value *>, const Value *V) {
124     return V->getType()->isIntOrIntVectorTy();
125   };
126   return {Pred, std::nullopt};
127 }
128 
boolOrVecBoolType()129 static inline SourcePred boolOrVecBoolType() {
130   auto Pred = [](ArrayRef<Value *>, const Value *V) {
131     return V->getType()->isIntOrIntVectorTy(1);
132   };
133   return {Pred, std::nullopt};
134 }
135 
anyFloatType()136 static inline SourcePred anyFloatType() {
137   auto Pred = [](ArrayRef<Value *>, const Value *V) {
138     return V->getType()->isFloatingPointTy();
139   };
140   auto Make = std::nullopt;
141   return {Pred, Make};
142 }
143 
anyFloatOrVecFloatType()144 static inline SourcePred anyFloatOrVecFloatType() {
145   auto Pred = [](ArrayRef<Value *>, const Value *V) {
146     return V->getType()->isFPOrFPVectorTy();
147   };
148   return {Pred, std::nullopt};
149 }
150 
anyPtrType()151 static inline SourcePred anyPtrType() {
152   auto Pred = [](ArrayRef<Value *>, const Value *V) {
153     return V->getType()->isPointerTy() && !V->isSwiftError();
154   };
155   auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) {
156     std::vector<Constant *> Result;
157     // TODO: Should these point at something?
158     for (Type *T : Ts)
159       Result.push_back(
160           PoisonValue::get(PointerType::getUnqual(T->getContext())));
161     return Result;
162   };
163   return {Pred, Make};
164 }
165 
sizedPtrType()166 static inline SourcePred sizedPtrType() {
167   auto Pred = [](ArrayRef<Value *>, const Value *V) {
168     if (V->isSwiftError())
169       return false;
170 
171     return V->getType()->isPointerTy();
172   };
173   auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) {
174     std::vector<Constant *> Result;
175 
176     // TODO: This doesn't really make sense with opaque pointers,
177     // as the pointer type will always be the same.
178     for (Type *T : Ts)
179       if (T->isSized())
180         Result.push_back(
181             PoisonValue::get(PointerType::getUnqual(T->getContext())));
182 
183     return Result;
184   };
185   return {Pred, Make};
186 }
187 
matchFirstLengthWAnyType()188 static inline SourcePred matchFirstLengthWAnyType() {
189   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
190     assert(!Cur.empty() && "No first source yet");
191     Type *This = V->getType(), *First = Cur[0]->getType();
192     VectorType *ThisVec = dyn_cast<VectorType>(This);
193     VectorType *FirstVec = dyn_cast<VectorType>(First);
194     if (ThisVec && FirstVec) {
195       return ThisVec->getElementCount() == FirstVec->getElementCount();
196     }
197     return (ThisVec == nullptr) && (FirstVec == nullptr) && (!This->isVoidTy());
198   };
199   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes) {
200     assert(!Cur.empty() && "No first source yet");
201     std::vector<Constant *> Result;
202     ElementCount EC;
203     bool isVec = false;
204     if (VectorType *VecTy = dyn_cast<VectorType>(Cur[0]->getType())) {
205       EC = VecTy->getElementCount();
206       isVec = true;
207     }
208     for (Type *T : BaseTypes) {
209       if (VectorType::isValidElementType(T)) {
210         if (isVec)
211           // If the first pred is <i1 x N>, make the result <T x N>
212           makeConstantsWithType(VectorType::get(T, EC), Result);
213         else
214           makeConstantsWithType(T, Result);
215       }
216     }
217     assert(!Result.empty() && "No potential constants.");
218     return Result;
219   };
220   return {Pred, Make};
221 }
222 
223 /// Match values that have the same type as the first source.
matchSecondType()224 static inline SourcePred matchSecondType() {
225   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
226     assert((Cur.size() > 1) && "No second source yet");
227     return V->getType() == Cur[1]->getType();
228   };
229   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
230     assert((Cur.size() > 1) && "No second source yet");
231     return makeConstantsWithType(Cur[1]->getType());
232   };
233   return {Pred, Make};
234 }
235 
anyAggregateType()236 static inline SourcePred anyAggregateType() {
237   auto Pred = [](ArrayRef<Value *>, const Value *V) {
238     // We can't index zero sized arrays.
239     if (isa<ArrayType>(V->getType()))
240       return V->getType()->getArrayNumElements() > 0;
241 
242     // Structs can also be zero sized. I.e opaque types.
243     if (isa<StructType>(V->getType()))
244       return V->getType()->getStructNumElements() > 0;
245 
246     return V->getType()->isAggregateType();
247   };
248   // TODO: For now we only find aggregates in BaseTypes. It might be better to
249   // manufacture them out of the base types in some cases.
250   auto Find = std::nullopt;
251   return {Pred, Find};
252 }
253 
anyVectorType()254 static inline SourcePred anyVectorType() {
255   auto Pred = [](ArrayRef<Value *>, const Value *V) {
256     return V->getType()->isVectorTy();
257   };
258   // TODO: For now we only find vectors in BaseTypes. It might be better to
259   // manufacture vectors out of the base types, but it's tricky to be sure
260   // that's actually a reasonable type.
261   auto Make = std::nullopt;
262   return {Pred, Make};
263 }
264 
265 /// Match values that have the same type as the first source.
matchFirstType()266 static inline SourcePred matchFirstType() {
267   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
268     assert(!Cur.empty() && "No first source yet");
269     return V->getType() == Cur[0]->getType();
270   };
271   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
272     assert(!Cur.empty() && "No first source yet");
273     return makeConstantsWithType(Cur[0]->getType());
274   };
275   return {Pred, Make};
276 }
277 
278 /// Match values that have the first source's scalar type.
matchScalarOfFirstType()279 static inline SourcePred matchScalarOfFirstType() {
280   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
281     assert(!Cur.empty() && "No first source yet");
282     return V->getType() == Cur[0]->getType()->getScalarType();
283   };
284   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
285     assert(!Cur.empty() && "No first source yet");
286     return makeConstantsWithType(Cur[0]->getType()->getScalarType());
287   };
288   return {Pred, Make};
289 }
290 
291 } // namespace fuzzerop
292 } // namespace llvm
293 
294 #endif // LLVM_FUZZMUTATE_OPDESCRIPTOR_H
295