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 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 SourcePred(PredT Pred, MakeT Make) : Pred(Pred), Make(Make) {} 62 SourcePred(PredT Pred, NoneType) : Pred(Pred) { 63 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 }; 75 } 76 77 /// Returns true if \c New is compatible for the argument after \c Cur 78 bool matches(ArrayRef<Value *> Cur, const Value *New) { 79 return Pred(Cur, New); 80 } 81 82 /// Generates a list of potential values for the argument after \c Cur. 83 std::vector<Constant *> generate(ArrayRef<Value *> Cur, 84 ArrayRef<Type *> BaseTypes) { 85 return Make(Cur, BaseTypes); 86 } 87 }; 88 89 /// A description of some operation we can build while fuzzing IR. 90 struct OpDescriptor { 91 unsigned Weight; 92 SmallVector<SourcePred, 2> SourcePreds; 93 std::function<Value *(ArrayRef<Value *>, Instruction *)> BuilderFunc; 94 }; 95 96 static inline SourcePred onlyType(Type *Only) { 97 auto Pred = [Only](ArrayRef<Value *>, const Value *V) { 98 return V->getType() == Only; 99 }; 100 auto Make = [Only](ArrayRef<Value *>, ArrayRef<Type *>) { 101 return makeConstantsWithType(Only); 102 }; 103 return {Pred, Make}; 104 } 105 106 static inline SourcePred anyType() { 107 auto Pred = [](ArrayRef<Value *>, const Value *V) { 108 return !V->getType()->isVoidTy(); 109 }; 110 auto Make = None; 111 return {Pred, Make}; 112 } 113 114 static inline SourcePred anyIntType() { 115 auto Pred = [](ArrayRef<Value *>, const Value *V) { 116 return V->getType()->isIntegerTy(); 117 }; 118 auto Make = None; 119 return {Pred, Make}; 120 } 121 122 static inline SourcePred anyFloatType() { 123 auto Pred = [](ArrayRef<Value *>, const Value *V) { 124 return V->getType()->isFloatingPointTy(); 125 }; 126 auto Make = None; 127 return {Pred, Make}; 128 } 129 130 static inline SourcePred anyPtrType() { 131 auto Pred = [](ArrayRef<Value *>, const Value *V) { 132 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 return {Pred, Make}; 142 } 143 144 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 return {Pred, Make}; 163 } 164 165 static inline SourcePred anyAggregateType() { 166 auto Pred = [](ArrayRef<Value *>, const Value *V) { 167 // We can't index zero sized arrays. 168 if (isa<ArrayType>(V->getType())) 169 return V->getType()->getArrayNumElements() > 0; 170 171 // Structs can also be zero sized. I.e opaque types. 172 if (isa<StructType>(V->getType())) 173 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 return {Pred, Find}; 181 } 182 183 static inline SourcePred anyVectorType() { 184 auto Pred = [](ArrayRef<Value *>, const Value *V) { 185 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 return {Pred, Make}; 192 } 193 194 /// Match values that have the same type as the first source. 195 static inline SourcePred matchFirstType() { 196 auto Pred = [](ArrayRef<Value *> Cur, const Value *V) { 197 assert(!Cur.empty() && "No first source yet"); 198 return V->getType() == Cur[0]->getType(); 199 }; 200 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) { 201 assert(!Cur.empty() && "No first source yet"); 202 return makeConstantsWithType(Cur[0]->getType()); 203 }; 204 return {Pred, Make}; 205 } 206 207 /// Match values that have the first source's scalar type. 208 static inline SourcePred matchScalarOfFirstType() { 209 auto Pred = [](ArrayRef<Value *> Cur, const Value *V) { 210 assert(!Cur.empty() && "No first source yet"); 211 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 return makeConstantsWithType(Cur[0]->getType()->getScalarType()); 216 }; 217 return {Pred, Make}; 218 } 219 220 } // end fuzzerop namespace 221 } // end llvm namespace 222 223 #endif // LLVM_FUZZMUTATE_OPDESCRIPTOR_H 224