1 //===-- OpDescriptor.h ------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Provides the fuzzerop::Descriptor class and related tools for describing
10 // operations an IR fuzzer can work with.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_FUZZMUTATE_OPDESCRIPTOR_H
15 #define LLVM_FUZZMUTATE_OPDESCRIPTOR_H
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"
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
);
36 /// A matcher/generator for finding suitable values for the next source in an
37 /// operation's partially completed argument list.
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
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
51 using MakeT
= std::function
<std::vector
<Constant
*>(
52 ArrayRef
<Value
*> Cur
, ArrayRef
<Type
*> BaseTypes
)>;
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
);
68 makeConstantsWithType(T
, Result
);
71 report_fatal_error("Predicate does not match for base types");
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
);
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
);
88 /// A description of some operation we can build while fuzzing IR.
91 SmallVector
<SourcePred
, 2> SourcePreds
;
92 std::function
<Value
*(ArrayRef
<Value
*>, BasicBlock::iterator
)> BuilderFunc
;
95 static inline SourcePred
onlyType(Type
*Only
) {
96 auto Pred
= [Only
](ArrayRef
<Value
*>, const Value
*V
) {
97 return V
->getType() == Only
;
99 auto Make
= [Only
](ArrayRef
<Value
*>, ArrayRef
<Type
*>) {
100 return makeConstantsWithType(Only
);
105 static inline SourcePred
anyType() {
106 auto Pred
= [](ArrayRef
<Value
*>, const Value
*V
) {
107 return !V
->getType()->isVoidTy();
109 auto Make
= std::nullopt
;
113 static inline SourcePred
anyIntType() {
114 auto Pred
= [](ArrayRef
<Value
*>, const Value
*V
) {
115 return V
->getType()->isIntegerTy();
117 auto Make
= std::nullopt
;
121 static inline SourcePred
anyIntOrVecIntType() {
122 auto Pred
= [](ArrayRef
<Value
*>, const Value
*V
) {
123 return V
->getType()->isIntOrIntVectorTy();
125 return {Pred
, std::nullopt
};
128 static inline SourcePred
boolOrVecBoolType() {
129 auto Pred
= [](ArrayRef
<Value
*>, const Value
*V
) {
130 return V
->getType()->isIntOrIntVectorTy(1);
132 return {Pred
, std::nullopt
};
135 static inline SourcePred
anyFloatType() {
136 auto Pred
= [](ArrayRef
<Value
*>, const Value
*V
) {
137 return V
->getType()->isFloatingPointTy();
139 auto Make
= std::nullopt
;
143 static inline SourcePred
anyFloatOrVecFloatType() {
144 auto Pred
= [](ArrayRef
<Value
*>, const Value
*V
) {
145 return V
->getType()->isFPOrFPVectorTy();
147 return {Pred
, std::nullopt
};
150 static inline SourcePred
anyPtrType() {
151 auto Pred
= [](ArrayRef
<Value
*>, const Value
*V
) {
152 return V
->getType()->isPointerTy() && !V
->isSwiftError();
154 auto Make
= [](ArrayRef
<Value
*>, ArrayRef
<Type
*> Ts
) {
155 std::vector
<Constant
*> Result
;
156 // TODO: Should these point at something?
158 Result
.push_back(PoisonValue::get(PointerType::getUnqual(T
)));
164 static inline SourcePred
sizedPtrType() {
165 auto Pred
= [](ArrayRef
<Value
*>, const Value
*V
) {
166 if (V
->isSwiftError())
169 return V
->getType()->isPointerTy();
171 auto Make
= [](ArrayRef
<Value
*>, ArrayRef
<Type
*> Ts
) {
172 std::vector
<Constant
*> Result
;
174 // TODO: This doesn't really make sense with opaque pointers,
175 // as the pointer type will always be the same.
178 Result
.push_back(PoisonValue::get(PointerType::getUnqual(T
)));
185 static 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
>(This
);
190 VectorType
*FirstVec
= dyn_cast
<VectorType
>(First
);
191 if (ThisVec
&& FirstVec
) {
192 return ThisVec
->getElementCount() == FirstVec
->getElementCount();
194 return (ThisVec
== nullptr) && (FirstVec
== nullptr) && (!This
->isVoidTy());
196 auto Make
= [](ArrayRef
<Value
*> Cur
, ArrayRef
<Type
*> BaseTypes
) {
197 assert(!Cur
.empty() && "No first source yet");
198 std::vector
<Constant
*> Result
;
201 if (VectorType
*VecTy
= dyn_cast
<VectorType
>(Cur
[0]->getType())) {
202 EC
= VecTy
->getElementCount();
205 for (Type
*T
: BaseTypes
) {
206 if (VectorType::isValidElementType(T
)) {
208 // If the first pred is <i1 x N>, make the result <T x N>
209 makeConstantsWithType(VectorType::get(T
, EC
), Result
);
211 makeConstantsWithType(T
, Result
);
214 assert(!Result
.empty() && "No potential constants.");
220 /// Match values that have the same type as the first source.
221 static 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();
226 auto Make
= [](ArrayRef
<Value
*> Cur
, ArrayRef
<Type
*>) {
227 assert((Cur
.size() > 1) && "No second source yet");
228 return makeConstantsWithType(Cur
[1]->getType());
233 static inline SourcePred
anyAggregateType() {
234 auto Pred
= [](ArrayRef
<Value
*>, const Value
*V
) {
235 // We can't index zero sized arrays.
236 if (isa
<ArrayType
>(V
->getType()))
237 return V
->getType()->getArrayNumElements() > 0;
239 // Structs can also be zero sized. I.e opaque types.
240 if (isa
<StructType
>(V
->getType()))
241 return V
->getType()->getStructNumElements() > 0;
243 return V
->getType()->isAggregateType();
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
;
251 static inline SourcePred
anyVectorType() {
252 auto Pred
= [](ArrayRef
<Value
*>, const Value
*V
) {
253 return V
->getType()->isVectorTy();
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
;
262 /// Match values that have the same type as the first source.
263 static 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();
268 auto Make
= [](ArrayRef
<Value
*> Cur
, ArrayRef
<Type
*>) {
269 assert(!Cur
.empty() && "No first source yet");
270 return makeConstantsWithType(Cur
[0]->getType());
275 /// Match values that have the first source's scalar type.
276 static 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();
281 auto Make
= [](ArrayRef
<Value
*> Cur
, ArrayRef
<Type
*>) {
282 assert(!Cur
.empty() && "No first source yet");
283 return makeConstantsWithType(Cur
[0]->getType()->getScalarType());
288 } // namespace fuzzerop
291 #endif // LLVM_FUZZMUTATE_OPDESCRIPTOR_H