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 = PoisonValue::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 *>, BasicBlock::iterator)> 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( 159 PoisonValue::get(PointerType::getUnqual(T->getContext()))); 160 return Result; 161 }; 162 return {Pred, Make}; 163 } 164 165 static inline SourcePred sizedPtrType() { 166 auto Pred = [](ArrayRef<Value *>, const Value *V) { 167 if (V->isSwiftError()) 168 return false; 169 170 return V->getType()->isPointerTy(); 171 }; 172 auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) { 173 std::vector<Constant *> Result; 174 175 // TODO: This doesn't really make sense with opaque pointers, 176 // as the pointer type will always be the same. 177 for (Type *T : Ts) 178 if (T->isSized()) 179 Result.push_back( 180 PoisonValue::get(PointerType::getUnqual(T->getContext()))); 181 182 return Result; 183 }; 184 return {Pred, Make}; 185 } 186 187 static inline SourcePred matchFirstLengthWAnyType() { 188 auto Pred = [](ArrayRef<Value *> Cur, const Value *V) { 189 assert(!Cur.empty() && "No first source yet"); 190 Type *This = V->getType(), *First = Cur[0]->getType(); 191 VectorType *ThisVec = dyn_cast<VectorType>(This); 192 VectorType *FirstVec = dyn_cast<VectorType>(First); 193 if (ThisVec && FirstVec) { 194 return ThisVec->getElementCount() == FirstVec->getElementCount(); 195 } 196 return (ThisVec == nullptr) && (FirstVec == nullptr) && (!This->isVoidTy()); 197 }; 198 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes) { 199 assert(!Cur.empty() && "No first source yet"); 200 std::vector<Constant *> Result; 201 ElementCount EC; 202 bool isVec = false; 203 if (VectorType *VecTy = dyn_cast<VectorType>(Cur[0]->getType())) { 204 EC = VecTy->getElementCount(); 205 isVec = true; 206 } 207 for (Type *T : BaseTypes) { 208 if (VectorType::isValidElementType(T)) { 209 if (isVec) 210 // If the first pred is <i1 x N>, make the result <T x N> 211 makeConstantsWithType(VectorType::get(T, EC), Result); 212 else 213 makeConstantsWithType(T, Result); 214 } 215 } 216 assert(!Result.empty() && "No potential constants."); 217 return Result; 218 }; 219 return {Pred, Make}; 220 } 221 222 /// Match values that have the same type as the first source. 223 static inline SourcePred matchSecondType() { 224 auto Pred = [](ArrayRef<Value *> Cur, const Value *V) { 225 assert((Cur.size() > 1) && "No second source yet"); 226 return V->getType() == Cur[1]->getType(); 227 }; 228 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) { 229 assert((Cur.size() > 1) && "No second source yet"); 230 return makeConstantsWithType(Cur[1]->getType()); 231 }; 232 return {Pred, Make}; 233 } 234 235 static inline SourcePred anyAggregateType() { 236 auto Pred = [](ArrayRef<Value *>, const Value *V) { 237 // We can't index zero sized arrays. 238 if (isa<ArrayType>(V->getType())) 239 return V->getType()->getArrayNumElements() > 0; 240 241 // Structs can also be zero sized. I.e opaque types. 242 if (isa<StructType>(V->getType())) 243 return V->getType()->getStructNumElements() > 0; 244 245 return V->getType()->isAggregateType(); 246 }; 247 // TODO: For now we only find aggregates in BaseTypes. It might be better to 248 // manufacture them out of the base types in some cases. 249 auto Find = std::nullopt; 250 return {Pred, Find}; 251 } 252 253 static inline SourcePred anyVectorType() { 254 auto Pred = [](ArrayRef<Value *>, const Value *V) { 255 return V->getType()->isVectorTy(); 256 }; 257 // TODO: For now we only find vectors in BaseTypes. It might be better to 258 // manufacture vectors out of the base types, but it's tricky to be sure 259 // that's actually a reasonable type. 260 auto Make = std::nullopt; 261 return {Pred, Make}; 262 } 263 264 /// Match values that have the same type as the first source. 265 static inline SourcePred matchFirstType() { 266 auto Pred = [](ArrayRef<Value *> Cur, const Value *V) { 267 assert(!Cur.empty() && "No first source yet"); 268 return V->getType() == Cur[0]->getType(); 269 }; 270 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) { 271 assert(!Cur.empty() && "No first source yet"); 272 return makeConstantsWithType(Cur[0]->getType()); 273 }; 274 return {Pred, Make}; 275 } 276 277 /// Match values that have the first source's scalar type. 278 static inline SourcePred matchScalarOfFirstType() { 279 auto Pred = [](ArrayRef<Value *> Cur, const Value *V) { 280 assert(!Cur.empty() && "No first source yet"); 281 return V->getType() == Cur[0]->getType()->getScalarType(); 282 }; 283 auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) { 284 assert(!Cur.empty() && "No first source yet"); 285 return makeConstantsWithType(Cur[0]->getType()->getScalarType()); 286 }; 287 return {Pred, Make}; 288 } 289 290 } // namespace fuzzerop 291 } // namespace llvm 292 293 #endif // LLVM_FUZZMUTATE_OPDESCRIPTOR_H 294