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/InstrTypes.h" 22 #include "llvm/IR/Type.h" 23 #include "llvm/IR/Value.h" 24 #include <functional> 25 26 namespace llvm { 27 class Instruction; 28 namespace fuzzerop { 29 30 /// @{ 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); 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. 43 class SourcePred { 44 public: 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 54 private: 55 PredT Pred; 56 MakeT Make; 57 58 public: 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 = UndefValue::get(T); 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. 89 struct OpDescriptor { 90 unsigned Weight; 91 SmallVector<SourcePred, 2> SourcePreds; 92 std::function<Value *(ArrayRef<Value *>, Instruction *)> BuilderFunc; 93 }; 94 95 static 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 105 static 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 113 static 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 121 static inline SourcePred anyIntOrVecIntType() { 122 auto Pred = [](ArrayRef<Value *>, const Value *V) { 123 return V->getType()->isIntOrIntVectorTy(); 124 }; 125 return {Pred, std::nullopt}; 126 } 127 128 static inline SourcePred boolOrVecBoolType() { 129 auto Pred = [](ArrayRef<Value *>, const Value *V) { 130 return V->getType()->isIntOrIntVectorTy(1); 131 }; 132 return {Pred, std::nullopt}; 133 } 134 135 static 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 143 static inline SourcePred anyFloatOrVecFloatType() { 144 auto Pred = [](ArrayRef<Value *>, const Value *V) { 145 return V->getType()->isFPOrFPVectorTy(); 146 }; 147 return {Pred, std::nullopt}; 148 } 149 150 static 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 164 static inline SourcePred sizedPtrType() { 165 auto Pred = [](ArrayRef<Value *>, const Value *V) { 166 if (V->isSwiftError()) 167 return false; 168 169 return V->getType()->isPointerTy(); 170 }; 171 auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) { 172 std::vector<Constant *> Result; 173 174 // TODO: This doesn't really make sense with opaque pointers, 175 // as the pointer type will always be the same. 176 for (Type *T : Ts) 177 if (T->isSized()) 178 Result.push_back(UndefValue::get(PointerType::getUnqual(T))); 179 180 return Result; 181 }; 182 return {Pred, Make}; 183 } 184 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(); 193 } 194 return (ThisVec == nullptr) && (FirstVec == nullptr) && (!This->isVoidTy()); 195 }; 196 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes) { 197 assert(!Cur.empty() && "No first source yet"); 198 std::vector<Constant *> Result; 199 ElementCount EC; 200 bool isVec = false; 201 if (VectorType *VecTy = dyn_cast<VectorType>(Cur[0]->getType())) { 202 EC = VecTy->getElementCount(); 203 isVec = true; 204 } 205 for (Type *T : BaseTypes) { 206 if (VectorType::isValidElementType(T)) { 207 if (isVec) 208 // If the first pred is <i1 x N>, make the result <T x N> 209 makeConstantsWithType(VectorType::get(T, EC), Result); 210 else 211 makeConstantsWithType(T, Result); 212 } 213 } 214 assert(!Result.empty() && "No potential constants."); 215 return Result; 216 }; 217 return {Pred, Make}; 218 } 219 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(); 225 }; 226 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) { 227 assert((Cur.size() > 1) && "No second source yet"); 228 return makeConstantsWithType(Cur[1]->getType()); 229 }; 230 return {Pred, Make}; 231 } 232 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; 238 239 // Structs can also be zero sized. I.e opaque types. 240 if (isa<StructType>(V->getType())) 241 return V->getType()->getStructNumElements() > 0; 242 243 return V->getType()->isAggregateType(); 244 }; 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; 248 return {Pred, Find}; 249 } 250 251 static inline SourcePred anyVectorType() { 252 auto Pred = [](ArrayRef<Value *>, const Value *V) { 253 return V->getType()->isVectorTy(); 254 }; 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; 259 return {Pred, Make}; 260 } 261 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(); 267 }; 268 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) { 269 assert(!Cur.empty() && "No first source yet"); 270 return makeConstantsWithType(Cur[0]->getType()); 271 }; 272 return {Pred, Make}; 273 } 274 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(); 280 }; 281 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) { 282 assert(!Cur.empty() && "No first source yet"); 283 return makeConstantsWithType(Cur[0]->getType()->getScalarType()); 284 }; 285 return {Pred, Make}; 286 } 287 288 } // namespace fuzzerop 289 } // namespace llvm 290 291 #endif // LLVM_FUZZMUTATE_OPDESCRIPTOR_H 292