LLVM 17.0.0git
OpDescriptor.h
Go to the documentation of this file.
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"
19#include "llvm/IR/Constants.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.
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) {
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.
90 unsigned Weight;
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(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
122 auto Pred = [](ArrayRef<Value *>, const Value *V) {
123 return V->getType()->isIntOrIntVectorTy();
124 };
125 return {Pred, std::nullopt};
126}
127
129 auto Pred = [](ArrayRef<Value *>, const Value *V) {
130 return V->getType()->isIntOrIntVectorTy(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
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(UndefValue::get(PointerType::getUnqual(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 if (const auto *PtrT = dyn_cast<PointerType>(V->getType()))
170 return PtrT->isOpaque() ||
171 PtrT->getNonOpaquePointerElementType()->isSized();
172 return false;
173 };
174 auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) {
175 std::vector<Constant *> Result;
176
177 for (Type *T : Ts)
178 if (T->isSized())
179 Result.push_back(UndefValue::get(PointerType::getUnqual(T)));
180
181 return Result;
182 };
183 return {Pred, Make};
184}
185
187 auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
188 assert(!Cur.empty() && "No first source yet");
189 Type *This = V->getType(), *First = Cur[0]->getType();
190 VectorType *ThisVec = dyn_cast<VectorType>(This);
191 VectorType *FirstVec = dyn_cast<VectorType>(First);
192 if (ThisVec && FirstVec) {
193 return ThisVec->getElementCount() == FirstVec->getElementCount();
194 }
195 return (ThisVec == nullptr) && (FirstVec == nullptr) && (!This->isVoidTy());
196 };
197 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes) {
198 assert(!Cur.empty() && "No first source yet");
199 std::vector<Constant *> Result;
200 ElementCount EC;
201 bool isVec = false;
202 if (VectorType *VecTy = dyn_cast<VectorType>(Cur[0]->getType())) {
203 EC = VecTy->getElementCount();
204 isVec = true;
205 }
206 for (Type *T : BaseTypes) {
208 if (isVec)
209 // If the first pred is <i1 x N>, make the result <T x N>
211 else
212 makeConstantsWithType(T, Result);
213 }
214 }
215 assert(!Result.empty() && "No potential constants.");
216 return Result;
217 };
218 return {Pred, Make};
219}
220
221/// Match values that have the same type as the first source.
223 auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
224 assert((Cur.size() > 1) && "No second source yet");
225 return V->getType() == Cur[1]->getType();
226 };
227 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
228 assert((Cur.size() > 1) && "No second source yet");
229 return makeConstantsWithType(Cur[1]->getType());
230 };
231 return {Pred, Make};
232}
233
235 auto Pred = [](ArrayRef<Value *>, const Value *V) {
236 // We can't index zero sized arrays.
237 if (isa<ArrayType>(V->getType()))
238 return V->getType()->getArrayNumElements() > 0;
239
240 // Structs can also be zero sized. I.e opaque types.
241 if (isa<StructType>(V->getType()))
242 return V->getType()->getStructNumElements() > 0;
243
244 return V->getType()->isAggregateType();
245 };
246 // TODO: For now we only find aggregates in BaseTypes. It might be better to
247 // manufacture them out of the base types in some cases.
248 auto Find = std::nullopt;
249 return {Pred, Find};
250}
251
252static inline SourcePred anyVectorType() {
253 auto Pred = [](ArrayRef<Value *>, const Value *V) {
254 return V->getType()->isVectorTy();
255 };
256 // TODO: For now we only find vectors in BaseTypes. It might be better to
257 // manufacture vectors out of the base types, but it's tricky to be sure
258 // that's actually a reasonable type.
259 auto Make = std::nullopt;
260 return {Pred, Make};
261}
262
263/// Match values that have the same type as the first source.
264static inline SourcePred matchFirstType() {
265 auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
266 assert(!Cur.empty() && "No first source yet");
267 return V->getType() == Cur[0]->getType();
268 };
269 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
270 assert(!Cur.empty() && "No first source yet");
271 return makeConstantsWithType(Cur[0]->getType());
272 };
273 return {Pred, Make};
274}
275
276/// Match values that have the first source's scalar type.
278 auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
279 assert(!Cur.empty() && "No first source yet");
280 return V->getType() == Cur[0]->getType()->getScalarType();
281 };
282 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
283 assert(!Cur.empty() && "No first source yet");
284 return makeConstantsWithType(Cur[0]->getType()->getScalarType());
285 };
286 return {Pred, Make};
287}
288
289} // namespace fuzzerop
290} // namespace llvm
291
292#endif // LLVM_FUZZMUTATE_OPDESCRIPTOR_H
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static const T * Find(StringRef S, ArrayRef< T > A)
Find KV in array using binary search.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallVector class.
static SymbolRef::Type getType(const Symbol *Sym)
Definition: TapiFile.cpp:40
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:163
bool empty() const
empty - Check if the array is empty.
Definition: ArrayRef.h:158
This is an important base class in LLVM.
Definition: Constant.h:41
static PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the default address space (address sp...
Definition: DerivedTypes.h:662
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
Definition: Constants.cpp:1724
LLVM Value Representation.
Definition: Value.h:74
Base class of all SIMD vector types.
Definition: DerivedTypes.h:400
static bool isValidElementType(Type *ElemTy)
Return true if the specified type is valid as a element type.
Definition: Type.cpp:745
ElementCount getElementCount() const
Return an ElementCount instance to represent the (possibly scalable) number of elements in the vector...
Definition: DerivedTypes.h:638
static VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
Definition: Type.cpp:738
A matcher/generator for finding suitable values for the next source in an operation's partially compl...
Definition: OpDescriptor.h:43
bool matches(ArrayRef< Value * > Cur, const Value *New)
Returns true if New is compatible for the argument after Cur.
Definition: OpDescriptor.h:77
std::function< std::vector< Constant * >(ArrayRef< Value * > Cur, ArrayRef< Type * > BaseTypes)> MakeT
Given a list of already selected operands and a set of valid base types for a fuzzer,...
Definition: OpDescriptor.h:52
SourcePred(PredT Pred, MakeT Make)
Create a fully general source predicate.
Definition: OpDescriptor.h:60
SourcePred(PredT Pred, std::nullopt_t)
Definition: OpDescriptor.h:61
std::vector< Constant * > generate(ArrayRef< Value * > Cur, ArrayRef< Type * > BaseTypes)
Generates a list of potential values for the argument after Cur.
Definition: OpDescriptor.h:82
std::function< bool(ArrayRef< Value * > Cur, const Value *New)> PredT
Given a list of already selected operands, returns whether a given new operand is suitable for the ne...
Definition: OpDescriptor.h:47
static SourcePred matchFirstLengthWAnyType()
Definition: OpDescriptor.h:186
static SourcePred anyFloatOrVecFloatType()
Definition: OpDescriptor.h:143
static SourcePred sizedPtrType()
Definition: OpDescriptor.h:164
void makeConstantsWithType(Type *T, std::vector< Constant * > &Cs)
static SourcePred anyAggregateType()
Definition: OpDescriptor.h:234
static SourcePred anyIntType()
Definition: OpDescriptor.h:113
static SourcePred matchScalarOfFirstType()
Match values that have the first source's scalar type.
Definition: OpDescriptor.h:277
static SourcePred onlyType(Type *Only)
Definition: OpDescriptor.h:95
static SourcePred anyIntOrVecIntType()
Definition: OpDescriptor.h:121
static SourcePred anyVectorType()
Definition: OpDescriptor.h:252
static SourcePred boolOrVecBoolType()
Definition: OpDescriptor.h:128
static SourcePred anyFloatType()
Definition: OpDescriptor.h:135
static SourcePred matchFirstType()
Match values that have the same type as the first source.
Definition: OpDescriptor.h:264
static SourcePred anyPtrType()
Definition: OpDescriptor.h:150
static SourcePred anyType()
Definition: OpDescriptor.h:105
static SourcePred matchSecondType()
Match values that have the same type as the first source.
Definition: OpDescriptor.h:222
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:145
A description of some operation we can build while fuzzing IR.
Definition: OpDescriptor.h:89
SmallVector< SourcePred, 2 > SourcePreds
Definition: OpDescriptor.h:91
std::function< Value *(ArrayRef< Value * >, Instruction *)> BuilderFunc
Definition: OpDescriptor.h:92