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