Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:56

0001 //===-- OpDescriptor.h ------------------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // Provides the fuzzerop::Descriptor class and related tools for describing
0010 // operations an IR fuzzer can work with.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_FUZZMUTATE_OPDESCRIPTOR_H
0015 #define LLVM_FUZZMUTATE_OPDESCRIPTOR_H
0016 
0017 #include "llvm/ADT/ArrayRef.h"
0018 #include "llvm/ADT/SmallVector.h"
0019 #include "llvm/IR/Constants.h"
0020 #include "llvm/IR/DerivedTypes.h"
0021 #include "llvm/IR/InstrTypes.h"
0022 #include "llvm/IR/Type.h"
0023 #include "llvm/IR/Value.h"
0024 #include <functional>
0025 
0026 namespace llvm {
0027 class Instruction;
0028 namespace fuzzerop {
0029 
0030 /// @{
0031 /// Populate a small list of potentially interesting constants of a given type.
0032 void makeConstantsWithType(Type *T, std::vector<Constant *> &Cs);
0033 std::vector<Constant *> makeConstantsWithType(Type *T);
0034 /// @}
0035 
0036 /// A matcher/generator for finding suitable values for the next source in an
0037 /// operation's partially completed argument list.
0038 ///
0039 /// Given that we're building some operation X and may have already filled some
0040 /// subset of its operands, this predicate determines if some value New is
0041 /// suitable for the next operand or generates a set of values that are
0042 /// suitable.
0043 class SourcePred {
0044 public:
0045   /// Given a list of already selected operands, returns whether a given new
0046   /// operand is suitable for the next operand.
0047   using PredT = std::function<bool(ArrayRef<Value *> Cur, const Value *New)>;
0048   /// Given a list of already selected operands and a set of valid base types
0049   /// for a fuzzer, generates a list of constants that could be used for the
0050   /// next operand.
0051   using MakeT = std::function<std::vector<Constant *>(
0052       ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes)>;
0053 
0054 private:
0055   PredT Pred;
0056   MakeT Make;
0057 
0058 public:
0059   /// Create a fully general source predicate.
0060   SourcePred(PredT Pred, MakeT Make) : Pred(Pred), Make(Make) {}
0061   SourcePred(PredT Pred, std::nullopt_t) : Pred(Pred) {
0062     Make = [Pred](ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes) {
0063       // Default filter just calls Pred on each of the base types.
0064       std::vector<Constant *> Result;
0065       for (Type *T : BaseTypes) {
0066         Constant *V = PoisonValue::get(T);
0067         if (Pred(Cur, V))
0068           makeConstantsWithType(T, Result);
0069       }
0070       if (Result.empty())
0071         report_fatal_error("Predicate does not match for base types");
0072       return Result;
0073     };
0074   }
0075 
0076   /// Returns true if \c New is compatible for the argument after \c Cur
0077   bool matches(ArrayRef<Value *> Cur, const Value *New) {
0078     return Pred(Cur, New);
0079   }
0080 
0081   /// Generates a list of potential values for the argument after \c Cur.
0082   std::vector<Constant *> generate(ArrayRef<Value *> Cur,
0083                                    ArrayRef<Type *> BaseTypes) {
0084     return Make(Cur, BaseTypes);
0085   }
0086 };
0087 
0088 /// A description of some operation we can build while fuzzing IR.
0089 struct OpDescriptor {
0090   unsigned Weight;
0091   SmallVector<SourcePred, 2> SourcePreds;
0092   std::function<Value *(ArrayRef<Value *>, BasicBlock::iterator)> BuilderFunc;
0093 };
0094 
0095 static inline SourcePred onlyType(Type *Only) {
0096   auto Pred = [Only](ArrayRef<Value *>, const Value *V) {
0097     return V->getType() == Only;
0098   };
0099   auto Make = [Only](ArrayRef<Value *>, ArrayRef<Type *>) {
0100     return makeConstantsWithType(Only);
0101   };
0102   return {Pred, Make};
0103 }
0104 
0105 static inline SourcePred anyType() {
0106   auto Pred = [](ArrayRef<Value *>, const Value *V) {
0107     return !V->getType()->isVoidTy();
0108   };
0109   auto Make = std::nullopt;
0110   return {Pred, Make};
0111 }
0112 
0113 static inline SourcePred anyIntType() {
0114   auto Pred = [](ArrayRef<Value *>, const Value *V) {
0115     return V->getType()->isIntegerTy();
0116   };
0117   auto Make = std::nullopt;
0118   return {Pred, Make};
0119 }
0120 
0121 static inline SourcePred anyIntOrVecIntType() {
0122   auto Pred = [](ArrayRef<Value *>, const Value *V) {
0123     return V->getType()->isIntOrIntVectorTy();
0124   };
0125   return {Pred, std::nullopt};
0126 }
0127 
0128 static inline SourcePred boolOrVecBoolType() {
0129   auto Pred = [](ArrayRef<Value *>, const Value *V) {
0130     return V->getType()->isIntOrIntVectorTy(1);
0131   };
0132   return {Pred, std::nullopt};
0133 }
0134 
0135 static inline SourcePred anyFloatType() {
0136   auto Pred = [](ArrayRef<Value *>, const Value *V) {
0137     return V->getType()->isFloatingPointTy();
0138   };
0139   auto Make = std::nullopt;
0140   return {Pred, Make};
0141 }
0142 
0143 static inline SourcePred anyFloatOrVecFloatType() {
0144   auto Pred = [](ArrayRef<Value *>, const Value *V) {
0145     return V->getType()->isFPOrFPVectorTy();
0146   };
0147   return {Pred, std::nullopt};
0148 }
0149 
0150 static inline SourcePred anyPtrType() {
0151   auto Pred = [](ArrayRef<Value *>, const Value *V) {
0152     return V->getType()->isPointerTy() && !V->isSwiftError();
0153   };
0154   auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) {
0155     std::vector<Constant *> Result;
0156     // TODO: Should these point at something?
0157     for (Type *T : Ts)
0158       Result.push_back(
0159           PoisonValue::get(PointerType::getUnqual(T->getContext())));
0160     return Result;
0161   };
0162   return {Pred, Make};
0163 }
0164 
0165 static inline SourcePred sizedPtrType() {
0166   auto Pred = [](ArrayRef<Value *>, const Value *V) {
0167     if (V->isSwiftError())
0168       return false;
0169 
0170     return V->getType()->isPointerTy();
0171   };
0172   auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) {
0173     std::vector<Constant *> Result;
0174 
0175     // TODO: This doesn't really make sense with opaque pointers,
0176     // as the pointer type will always be the same.
0177     for (Type *T : Ts)
0178       if (T->isSized())
0179         Result.push_back(
0180             PoisonValue::get(PointerType::getUnqual(T->getContext())));
0181 
0182     return Result;
0183   };
0184   return {Pred, Make};
0185 }
0186 
0187 static inline SourcePred matchFirstLengthWAnyType() {
0188   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
0189     assert(!Cur.empty() && "No first source yet");
0190     Type *This = V->getType(), *First = Cur[0]->getType();
0191     VectorType *ThisVec = dyn_cast<VectorType>(This);
0192     VectorType *FirstVec = dyn_cast<VectorType>(First);
0193     if (ThisVec && FirstVec) {
0194       return ThisVec->getElementCount() == FirstVec->getElementCount();
0195     }
0196     return (ThisVec == nullptr) && (FirstVec == nullptr) && (!This->isVoidTy());
0197   };
0198   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes) {
0199     assert(!Cur.empty() && "No first source yet");
0200     std::vector<Constant *> Result;
0201     ElementCount EC;
0202     bool isVec = false;
0203     if (VectorType *VecTy = dyn_cast<VectorType>(Cur[0]->getType())) {
0204       EC = VecTy->getElementCount();
0205       isVec = true;
0206     }
0207     for (Type *T : BaseTypes) {
0208       if (VectorType::isValidElementType(T)) {
0209         if (isVec)
0210           // If the first pred is <i1 x N>, make the result <T x N>
0211           makeConstantsWithType(VectorType::get(T, EC), Result);
0212         else
0213           makeConstantsWithType(T, Result);
0214       }
0215     }
0216     assert(!Result.empty() && "No potential constants.");
0217     return Result;
0218   };
0219   return {Pred, Make};
0220 }
0221 
0222 /// Match values that have the same type as the first source.
0223 static inline SourcePred matchSecondType() {
0224   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
0225     assert((Cur.size() > 1) && "No second source yet");
0226     return V->getType() == Cur[1]->getType();
0227   };
0228   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
0229     assert((Cur.size() > 1) && "No second source yet");
0230     return makeConstantsWithType(Cur[1]->getType());
0231   };
0232   return {Pred, Make};
0233 }
0234 
0235 static inline SourcePred anyAggregateType() {
0236   auto Pred = [](ArrayRef<Value *>, const Value *V) {
0237     // We can't index zero sized arrays.
0238     if (isa<ArrayType>(V->getType()))
0239       return V->getType()->getArrayNumElements() > 0;
0240 
0241     // Structs can also be zero sized. I.e opaque types.
0242     if (isa<StructType>(V->getType()))
0243       return V->getType()->getStructNumElements() > 0;
0244 
0245     return V->getType()->isAggregateType();
0246   };
0247   // TODO: For now we only find aggregates in BaseTypes. It might be better to
0248   // manufacture them out of the base types in some cases.
0249   auto Find = std::nullopt;
0250   return {Pred, Find};
0251 }
0252 
0253 static inline SourcePred anyVectorType() {
0254   auto Pred = [](ArrayRef<Value *>, const Value *V) {
0255     return V->getType()->isVectorTy();
0256   };
0257   // TODO: For now we only find vectors in BaseTypes. It might be better to
0258   // manufacture vectors out of the base types, but it's tricky to be sure
0259   // that's actually a reasonable type.
0260   auto Make = std::nullopt;
0261   return {Pred, Make};
0262 }
0263 
0264 /// Match values that have the same type as the first source.
0265 static inline SourcePred matchFirstType() {
0266   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
0267     assert(!Cur.empty() && "No first source yet");
0268     return V->getType() == Cur[0]->getType();
0269   };
0270   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
0271     assert(!Cur.empty() && "No first source yet");
0272     return makeConstantsWithType(Cur[0]->getType());
0273   };
0274   return {Pred, Make};
0275 }
0276 
0277 /// Match values that have the first source's scalar type.
0278 static inline SourcePred matchScalarOfFirstType() {
0279   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
0280     assert(!Cur.empty() && "No first source yet");
0281     return V->getType() == Cur[0]->getType()->getScalarType();
0282   };
0283   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
0284     assert(!Cur.empty() && "No first source yet");
0285     return makeConstantsWithType(Cur[0]->getType()->getScalarType());
0286   };
0287   return {Pred, Make};
0288 }
0289 
0290 } // namespace fuzzerop
0291 } // namespace llvm
0292 
0293 #endif // LLVM_FUZZMUTATE_OPDESCRIPTOR_H