LLVM  16.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"
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 *>(
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) {
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;
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.
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
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1199
llvm::fuzzerop::makeConstantsWithType
void makeConstantsWithType(Type *T, std::vector< Constant * > &Cs)
Definition: OpDescriptor.cpp:15
llvm::fuzzerop::SourcePred::SourcePred
SourcePred(PredT Pred, std::nullopt_t)
Definition: OpDescriptor.h:60
llvm::Type
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
T
#define T
Definition: Mips16ISelLowering.cpp:341
llvm::fuzzerop::anyFloatType
static SourcePred anyFloatType()
Definition: OpDescriptor.h:120
llvm::fuzzerop::matchFirstType
static SourcePred matchFirstType()
Match values that have the same type as the first source.
Definition: OpDescriptor.h:194
llvm::ArrayRef::empty
bool empty() const
empty - Check if the array is empty.
Definition: ArrayRef.h:159
llvm::fuzzerop::anyIntType
static SourcePred anyIntType()
Definition: OpDescriptor.h:112
Constants.h
llvm::fuzzerop::OpDescriptor::BuilderFunc
std::function< Value *(ArrayRef< Value * >, Instruction *)> BuilderFunc
Definition: OpDescriptor.h:91
llvm::fuzzerop::anyType
static SourcePred anyType()
Definition: OpDescriptor.h:104
llvm::fuzzerop::SourcePred::PredT
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:46
llvm::fuzzerop::sizedPtrType
static SourcePred sizedPtrType()
Definition: OpDescriptor.h:142
llvm::fuzzerop::OpDescriptor
A description of some operation we can build while fuzzing IR.
Definition: OpDescriptor.h:88
llvm::Instruction
Definition: Instruction.h:42
llvm::report_fatal_error
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:145
llvm::UndefValue::get
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
Definition: Constants.cpp:1713
Type.h
llvm::Constant
This is an important base class in LLVM.
Definition: Constant.h:41
llvm::PointerType::getUnqual
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:651
llvm::fuzzerop::SourcePred::SourcePred
SourcePred(PredT Pred, MakeT Make)
Create a fully general source predicate.
Definition: OpDescriptor.h:59
ArrayRef.h
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
function
print Print MemDeps of function
Definition: MemDepPrinter.cpp:82
Find
static const T * Find(StringRef S, ArrayRef< T > A)
Find KV in array using binary search.
Definition: MCSubtargetInfo.cpp:26
getType
static M68kRelType getType(unsigned Kind, MCSymbolRefExpr::VariantKind &Modifier, bool &IsPCRel)
Definition: M68kELFObjectWriter.cpp:48
llvm::ArrayRef
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: APInt.h:32
llvm::fuzzerop::OpDescriptor::SourcePreds
SmallVector< SourcePred, 2 > SourcePreds
Definition: OpDescriptor.h:90
llvm::fuzzerop::SourcePred::matches
bool matches(ArrayRef< Value * > Cur, const Value *New)
Returns true if New is compatible for the argument after Cur.
Definition: OpDescriptor.h:76
llvm::fuzzerop::OpDescriptor::Weight
unsigned Weight
Definition: OpDescriptor.h:89
llvm::fuzzerop::SourcePred
A matcher/generator for finding suitable values for the next source in an operation's partially compl...
Definition: OpDescriptor.h:42
llvm::fuzzerop::onlyType
static SourcePred onlyType(Type *Only)
Definition: OpDescriptor.h:94
SmallVector.h
llvm::fuzzerop::anyPtrType
static SourcePred anyPtrType()
Definition: OpDescriptor.h:128
llvm::fuzzerop::SourcePred::MakeT
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:51
llvm::fuzzerop::SourcePred::generate
std::vector< Constant * > generate(ArrayRef< Value * > Cur, ArrayRef< Type * > BaseTypes)
Generates a list of potential values for the argument after Cur.
Definition: OpDescriptor.h:81
DerivedTypes.h
llvm::fuzzerop::anyAggregateType
static SourcePred anyAggregateType()
Definition: OpDescriptor.h:164
Value.h
llvm::Value
LLVM Value Representation.
Definition: Value.h:74
llvm::fuzzerop::anyVectorType
static SourcePred anyVectorType()
Definition: OpDescriptor.h:182
llvm::fuzzerop::matchScalarOfFirstType
static SourcePred matchScalarOfFirstType()
Match values that have the first source's scalar type.
Definition: OpDescriptor.h:207