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
26namespace llvm {
27class Instruction;
28namespace fuzzerop {
29
30/// @{
31/// Populate a small list of potentially interesting constants of a given type.
32void makeConstantsWithType(Type *T, std::vector<Constant *> &Cs);
33std::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.
43class SourcePred {
44public:
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
54private:
55 PredT Pred;
56 MakeT Make;
57
58public:
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 = UndefValue::get(T);
67 if (Pred(Cur, V))
68 makeConstantsWithType(T, Cs&: Result);
69 }
70 if (Result.empty())
71 report_fatal_error(reason: "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.
89struct OpDescriptor {
90 unsigned Weight;
91 SmallVector<SourcePred, 2> SourcePreds;
92 std::function<Value *(ArrayRef<Value *>, Instruction *)> BuilderFunc;
93};
94
95static 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(T: Only);
101 };
102 return {Pred, Make};
103}
104
105static 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
113static 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
121static inline SourcePred anyIntOrVecIntType() {
122 auto Pred = [](ArrayRef<Value *>, const Value *V) {
123 return V->getType()->isIntOrIntVectorTy();
124 };
125 return {Pred, std::nullopt};
126}
127
128static inline SourcePred boolOrVecBoolType() {
129 auto Pred = [](ArrayRef<Value *>, const Value *V) {
130 return V->getType()->isIntOrIntVectorTy(BitWidth: 1);
131 };
132 return {Pred, std::nullopt};
133}
134
135static 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
143static inline SourcePred anyFloatOrVecFloatType() {
144 auto Pred = [](ArrayRef<Value *>, const Value *V) {
145 return V->getType()->isFPOrFPVectorTy();
146 };
147 return {Pred, std::nullopt};
148}
149
150static 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(x: UndefValue::get(T: PointerType::getUnqual(ElementType: T)));
159 return Result;
160 };
161 return {Pred, Make};
162}
163
164static inline SourcePred sizedPtrType() {
165 auto Pred = [](ArrayRef<Value *>, const Value *V) {
166 if (V->isSwiftError())
167 return false;
168
169 return V->getType()->isPointerTy();
170 };
171 auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) {
172 std::vector<Constant *> Result;
173
174 // TODO: This doesn't really make sense with opaque pointers,
175 // as the pointer type will always be the same.
176 for (Type *T : Ts)
177 if (T->isSized())
178 Result.push_back(x: UndefValue::get(T: PointerType::getUnqual(ElementType: T)));
179
180 return Result;
181 };
182 return {Pred, Make};
183}
184
185static inline SourcePred matchFirstLengthWAnyType() {
186 auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
187 assert(!Cur.empty() && "No first source yet");
188 Type *This = V->getType(), *First = Cur[0]->getType();
189 VectorType *ThisVec = dyn_cast<VectorType>(Val: This);
190 VectorType *FirstVec = dyn_cast<VectorType>(Val: First);
191 if (ThisVec && FirstVec) {
192 return ThisVec->getElementCount() == FirstVec->getElementCount();
193 }
194 return (ThisVec == nullptr) && (FirstVec == nullptr) && (!This->isVoidTy());
195 };
196 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes) {
197 assert(!Cur.empty() && "No first source yet");
198 std::vector<Constant *> Result;
199 ElementCount EC;
200 bool isVec = false;
201 if (VectorType *VecTy = dyn_cast<VectorType>(Val: Cur[0]->getType())) {
202 EC = VecTy->getElementCount();
203 isVec = true;
204 }
205 for (Type *T : BaseTypes) {
206 if (VectorType::isValidElementType(ElemTy: T)) {
207 if (isVec)
208 // If the first pred is <i1 x N>, make the result <T x N>
209 makeConstantsWithType(T: VectorType::get(ElementType: T, EC), Cs&: Result);
210 else
211 makeConstantsWithType(T, Cs&: Result);
212 }
213 }
214 assert(!Result.empty() && "No potential constants.");
215 return Result;
216 };
217 return {Pred, Make};
218}
219
220/// Match values that have the same type as the first source.
221static inline SourcePred matchSecondType() {
222 auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
223 assert((Cur.size() > 1) && "No second source yet");
224 return V->getType() == Cur[1]->getType();
225 };
226 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
227 assert((Cur.size() > 1) && "No second source yet");
228 return makeConstantsWithType(T: Cur[1]->getType());
229 };
230 return {Pred, Make};
231}
232
233static inline SourcePred anyAggregateType() {
234 auto Pred = [](ArrayRef<Value *>, const Value *V) {
235 // We can't index zero sized arrays.
236 if (isa<ArrayType>(Val: V->getType()))
237 return V->getType()->getArrayNumElements() > 0;
238
239 // Structs can also be zero sized. I.e opaque types.
240 if (isa<StructType>(Val: V->getType()))
241 return V->getType()->getStructNumElements() > 0;
242
243 return V->getType()->isAggregateType();
244 };
245 // TODO: For now we only find aggregates in BaseTypes. It might be better to
246 // manufacture them out of the base types in some cases.
247 auto Find = std::nullopt;
248 return {Pred, Find};
249}
250
251static inline SourcePred anyVectorType() {
252 auto Pred = [](ArrayRef<Value *>, const Value *V) {
253 return V->getType()->isVectorTy();
254 };
255 // TODO: For now we only find vectors in BaseTypes. It might be better to
256 // manufacture vectors out of the base types, but it's tricky to be sure
257 // that's actually a reasonable type.
258 auto Make = std::nullopt;
259 return {Pred, Make};
260}
261
262/// Match values that have the same type as the first source.
263static inline SourcePred matchFirstType() {
264 auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
265 assert(!Cur.empty() && "No first source yet");
266 return V->getType() == Cur[0]->getType();
267 };
268 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
269 assert(!Cur.empty() && "No first source yet");
270 return makeConstantsWithType(T: Cur[0]->getType());
271 };
272 return {Pred, Make};
273}
274
275/// Match values that have the first source's scalar type.
276static inline SourcePred matchScalarOfFirstType() {
277 auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
278 assert(!Cur.empty() && "No first source yet");
279 return V->getType() == Cur[0]->getType()->getScalarType();
280 };
281 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
282 assert(!Cur.empty() && "No first source yet");
283 return makeConstantsWithType(T: Cur[0]->getType()->getScalarType());
284 };
285 return {Pred, Make};
286}
287
288} // namespace fuzzerop
289} // namespace llvm
290
291#endif // LLVM_FUZZMUTATE_OPDESCRIPTOR_H
292

source code of llvm/include/llvm/FuzzMutate/OpDescriptor.h