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