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 *>( 51 ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes)>; 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) { 65 Constant *V = UndefValue::get(T); 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; 90 SmallVector<SourcePred, 2> SourcePreds; 91 std::function<Value *(ArrayRef<Value *>, Instruction *)> BuilderFunc; 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. 207 static inline SourcePred matchScalarOfFirstType() { 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 223