10b57cec5SDimitry Andric //===-- OpDescriptor.h ------------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Provides the fuzzerop::Descriptor class and related tools for describing
100b57cec5SDimitry Andric // operations an IR fuzzer can work with.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #ifndef LLVM_FUZZMUTATE_OPDESCRIPTOR_H
150b57cec5SDimitry Andric #define LLVM_FUZZMUTATE_OPDESCRIPTOR_H
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
180b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
190b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
200b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h"
2106c3fb27SDimitry Andric #include "llvm/IR/InstrTypes.h"
220b57cec5SDimitry Andric #include "llvm/IR/Type.h"
230b57cec5SDimitry Andric #include "llvm/IR/Value.h"
240b57cec5SDimitry Andric #include <functional>
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric namespace llvm {
2781ad6265SDimitry Andric class Instruction;
280b57cec5SDimitry Andric namespace fuzzerop {
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric /// @{
310b57cec5SDimitry Andric /// Populate a small list of potentially interesting constants of a given type.
320b57cec5SDimitry Andric void makeConstantsWithType(Type *T, std::vector<Constant *> &Cs);
330b57cec5SDimitry Andric std::vector<Constant *> makeConstantsWithType(Type *T);
340b57cec5SDimitry Andric /// @}
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric /// A matcher/generator for finding suitable values for the next source in an
370b57cec5SDimitry Andric /// operation's partially completed argument list.
380b57cec5SDimitry Andric ///
390b57cec5SDimitry Andric /// Given that we're building some operation X and may have already filled some
400b57cec5SDimitry Andric /// subset of its operands, this predicate determines if some value New is
410b57cec5SDimitry Andric /// suitable for the next operand or generates a set of values that are
420b57cec5SDimitry Andric /// suitable.
430b57cec5SDimitry Andric class SourcePred {
440b57cec5SDimitry Andric public:
450b57cec5SDimitry Andric   /// Given a list of already selected operands, returns whether a given new
460b57cec5SDimitry Andric   /// operand is suitable for the next operand.
470b57cec5SDimitry Andric   using PredT = std::function<bool(ArrayRef<Value *> Cur, const Value *New)>;
480b57cec5SDimitry Andric   /// Given a list of already selected operands and a set of valid base types
490b57cec5SDimitry Andric   /// for a fuzzer, generates a list of constants that could be used for the
500b57cec5SDimitry Andric   /// next operand.
510b57cec5SDimitry Andric   using MakeT = std::function<std::vector<Constant *>(
520b57cec5SDimitry Andric       ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes)>;
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric private:
550b57cec5SDimitry Andric   PredT Pred;
560b57cec5SDimitry Andric   MakeT Make;
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric public:
590b57cec5SDimitry Andric   /// Create a fully general source predicate.
SourcePred(PredT Pred,MakeT Make)600b57cec5SDimitry Andric   SourcePred(PredT Pred, MakeT Make) : Pred(Pred), Make(Make) {}
SourcePred(PredT Pred,std::nullopt_t)61bdd1243dSDimitry Andric   SourcePred(PredT Pred, std::nullopt_t) : Pred(Pred) {
620b57cec5SDimitry Andric     Make = [Pred](ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes) {
630b57cec5SDimitry Andric       // Default filter just calls Pred on each of the base types.
640b57cec5SDimitry Andric       std::vector<Constant *> Result;
650b57cec5SDimitry Andric       for (Type *T : BaseTypes) {
660b57cec5SDimitry Andric         Constant *V = UndefValue::get(T);
670b57cec5SDimitry Andric         if (Pred(Cur, V))
680b57cec5SDimitry Andric           makeConstantsWithType(T, Result);
690b57cec5SDimitry Andric       }
700b57cec5SDimitry Andric       if (Result.empty())
710b57cec5SDimitry Andric         report_fatal_error("Predicate does not match for base types");
720b57cec5SDimitry Andric       return Result;
730b57cec5SDimitry Andric     };
740b57cec5SDimitry Andric   }
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   /// Returns true if \c New is compatible for the argument after \c Cur
matches(ArrayRef<Value * > Cur,const Value * New)770b57cec5SDimitry Andric   bool matches(ArrayRef<Value *> Cur, const Value *New) {
780b57cec5SDimitry Andric     return Pred(Cur, New);
790b57cec5SDimitry Andric   }
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric   /// Generates a list of potential values for the argument after \c Cur.
generate(ArrayRef<Value * > Cur,ArrayRef<Type * > BaseTypes)820b57cec5SDimitry Andric   std::vector<Constant *> generate(ArrayRef<Value *> Cur,
830b57cec5SDimitry Andric                                    ArrayRef<Type *> BaseTypes) {
840b57cec5SDimitry Andric     return Make(Cur, BaseTypes);
850b57cec5SDimitry Andric   }
860b57cec5SDimitry Andric };
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric /// A description of some operation we can build while fuzzing IR.
890b57cec5SDimitry Andric struct OpDescriptor {
900b57cec5SDimitry Andric   unsigned Weight;
910b57cec5SDimitry Andric   SmallVector<SourcePred, 2> SourcePreds;
920b57cec5SDimitry Andric   std::function<Value *(ArrayRef<Value *>, Instruction *)> BuilderFunc;
930b57cec5SDimitry Andric };
940b57cec5SDimitry Andric 
onlyType(Type * Only)950b57cec5SDimitry Andric static inline SourcePred onlyType(Type *Only) {
960b57cec5SDimitry Andric   auto Pred = [Only](ArrayRef<Value *>, const Value *V) {
970b57cec5SDimitry Andric     return V->getType() == Only;
980b57cec5SDimitry Andric   };
990b57cec5SDimitry Andric   auto Make = [Only](ArrayRef<Value *>, ArrayRef<Type *>) {
1000b57cec5SDimitry Andric     return makeConstantsWithType(Only);
1010b57cec5SDimitry Andric   };
1020b57cec5SDimitry Andric   return {Pred, Make};
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric 
anyType()1050b57cec5SDimitry Andric static inline SourcePred anyType() {
1060b57cec5SDimitry Andric   auto Pred = [](ArrayRef<Value *>, const Value *V) {
1070b57cec5SDimitry Andric     return !V->getType()->isVoidTy();
1080b57cec5SDimitry Andric   };
109bdd1243dSDimitry Andric   auto Make = std::nullopt;
1100b57cec5SDimitry Andric   return {Pred, Make};
1110b57cec5SDimitry Andric }
1120b57cec5SDimitry Andric 
anyIntType()1130b57cec5SDimitry Andric static inline SourcePred anyIntType() {
1140b57cec5SDimitry Andric   auto Pred = [](ArrayRef<Value *>, const Value *V) {
1150b57cec5SDimitry Andric     return V->getType()->isIntegerTy();
1160b57cec5SDimitry Andric   };
117bdd1243dSDimitry Andric   auto Make = std::nullopt;
1180b57cec5SDimitry Andric   return {Pred, Make};
1190b57cec5SDimitry Andric }
1200b57cec5SDimitry Andric 
anyIntOrVecIntType()12106c3fb27SDimitry Andric static inline SourcePred anyIntOrVecIntType() {
12206c3fb27SDimitry Andric   auto Pred = [](ArrayRef<Value *>, const Value *V) {
12306c3fb27SDimitry Andric     return V->getType()->isIntOrIntVectorTy();
12406c3fb27SDimitry Andric   };
12506c3fb27SDimitry Andric   return {Pred, std::nullopt};
12606c3fb27SDimitry Andric }
12706c3fb27SDimitry Andric 
boolOrVecBoolType()12806c3fb27SDimitry Andric static inline SourcePred boolOrVecBoolType() {
12906c3fb27SDimitry Andric   auto Pred = [](ArrayRef<Value *>, const Value *V) {
13006c3fb27SDimitry Andric     return V->getType()->isIntOrIntVectorTy(1);
13106c3fb27SDimitry Andric   };
13206c3fb27SDimitry Andric   return {Pred, std::nullopt};
13306c3fb27SDimitry Andric }
13406c3fb27SDimitry Andric 
anyFloatType()1350b57cec5SDimitry Andric static inline SourcePred anyFloatType() {
1360b57cec5SDimitry Andric   auto Pred = [](ArrayRef<Value *>, const Value *V) {
1370b57cec5SDimitry Andric     return V->getType()->isFloatingPointTy();
1380b57cec5SDimitry Andric   };
139bdd1243dSDimitry Andric   auto Make = std::nullopt;
1400b57cec5SDimitry Andric   return {Pred, Make};
1410b57cec5SDimitry Andric }
1420b57cec5SDimitry Andric 
anyFloatOrVecFloatType()14306c3fb27SDimitry Andric static inline SourcePred anyFloatOrVecFloatType() {
14406c3fb27SDimitry Andric   auto Pred = [](ArrayRef<Value *>, const Value *V) {
14506c3fb27SDimitry Andric     return V->getType()->isFPOrFPVectorTy();
14606c3fb27SDimitry Andric   };
14706c3fb27SDimitry Andric   return {Pred, std::nullopt};
14806c3fb27SDimitry Andric }
14906c3fb27SDimitry Andric 
anyPtrType()1500b57cec5SDimitry Andric static inline SourcePred anyPtrType() {
1510b57cec5SDimitry Andric   auto Pred = [](ArrayRef<Value *>, const Value *V) {
1520b57cec5SDimitry Andric     return V->getType()->isPointerTy() && !V->isSwiftError();
1530b57cec5SDimitry Andric   };
1540b57cec5SDimitry Andric   auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) {
1550b57cec5SDimitry Andric     std::vector<Constant *> Result;
1560b57cec5SDimitry Andric     // TODO: Should these point at something?
1570b57cec5SDimitry Andric     for (Type *T : Ts)
1580b57cec5SDimitry Andric       Result.push_back(UndefValue::get(PointerType::getUnqual(T)));
1590b57cec5SDimitry Andric     return Result;
1600b57cec5SDimitry Andric   };
1610b57cec5SDimitry Andric   return {Pred, Make};
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric 
sizedPtrType()1640b57cec5SDimitry Andric static inline SourcePred sizedPtrType() {
1650b57cec5SDimitry Andric   auto Pred = [](ArrayRef<Value *>, const Value *V) {
1660b57cec5SDimitry Andric     if (V->isSwiftError())
1670b57cec5SDimitry Andric       return false;
1680b57cec5SDimitry Andric 
16906c3fb27SDimitry Andric     return V->getType()->isPointerTy();
1700b57cec5SDimitry Andric   };
1710b57cec5SDimitry Andric   auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) {
1720b57cec5SDimitry Andric     std::vector<Constant *> Result;
1730b57cec5SDimitry Andric 
17406c3fb27SDimitry Andric     // TODO: This doesn't really make sense with opaque pointers,
17506c3fb27SDimitry Andric     // as the pointer type will always be the same.
1760b57cec5SDimitry Andric     for (Type *T : Ts)
1770b57cec5SDimitry Andric       if (T->isSized())
1780b57cec5SDimitry Andric         Result.push_back(UndefValue::get(PointerType::getUnqual(T)));
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric     return Result;
1810b57cec5SDimitry Andric   };
1820b57cec5SDimitry Andric   return {Pred, Make};
1830b57cec5SDimitry Andric }
1840b57cec5SDimitry Andric 
matchFirstLengthWAnyType()18506c3fb27SDimitry Andric static inline SourcePred matchFirstLengthWAnyType() {
18606c3fb27SDimitry Andric   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
18706c3fb27SDimitry Andric     assert(!Cur.empty() && "No first source yet");
18806c3fb27SDimitry Andric     Type *This = V->getType(), *First = Cur[0]->getType();
18906c3fb27SDimitry Andric     VectorType *ThisVec = dyn_cast<VectorType>(This);
19006c3fb27SDimitry Andric     VectorType *FirstVec = dyn_cast<VectorType>(First);
19106c3fb27SDimitry Andric     if (ThisVec && FirstVec) {
19206c3fb27SDimitry Andric       return ThisVec->getElementCount() == FirstVec->getElementCount();
19306c3fb27SDimitry Andric     }
19406c3fb27SDimitry Andric     return (ThisVec == nullptr) && (FirstVec == nullptr) && (!This->isVoidTy());
19506c3fb27SDimitry Andric   };
19606c3fb27SDimitry Andric   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes) {
19706c3fb27SDimitry Andric     assert(!Cur.empty() && "No first source yet");
19806c3fb27SDimitry Andric     std::vector<Constant *> Result;
19906c3fb27SDimitry Andric     ElementCount EC;
20006c3fb27SDimitry Andric     bool isVec = false;
20106c3fb27SDimitry Andric     if (VectorType *VecTy = dyn_cast<VectorType>(Cur[0]->getType())) {
20206c3fb27SDimitry Andric       EC = VecTy->getElementCount();
20306c3fb27SDimitry Andric       isVec = true;
20406c3fb27SDimitry Andric     }
20506c3fb27SDimitry Andric     for (Type *T : BaseTypes) {
20606c3fb27SDimitry Andric       if (VectorType::isValidElementType(T)) {
20706c3fb27SDimitry Andric         if (isVec)
20806c3fb27SDimitry Andric           // If the first pred is <i1 x N>, make the result <T x N>
20906c3fb27SDimitry Andric           makeConstantsWithType(VectorType::get(T, EC), Result);
21006c3fb27SDimitry Andric         else
21106c3fb27SDimitry Andric           makeConstantsWithType(T, Result);
21206c3fb27SDimitry Andric       }
21306c3fb27SDimitry Andric     }
21406c3fb27SDimitry Andric     assert(!Result.empty() && "No potential constants.");
21506c3fb27SDimitry Andric     return Result;
21606c3fb27SDimitry Andric   };
21706c3fb27SDimitry Andric   return {Pred, Make};
21806c3fb27SDimitry Andric }
21906c3fb27SDimitry Andric 
22006c3fb27SDimitry Andric /// Match values that have the same type as the first source.
matchSecondType()22106c3fb27SDimitry Andric static inline SourcePred matchSecondType() {
22206c3fb27SDimitry Andric   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
22306c3fb27SDimitry Andric     assert((Cur.size() > 1) && "No second source yet");
22406c3fb27SDimitry Andric     return V->getType() == Cur[1]->getType();
22506c3fb27SDimitry Andric   };
22606c3fb27SDimitry Andric   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
22706c3fb27SDimitry Andric     assert((Cur.size() > 1) && "No second source yet");
22806c3fb27SDimitry Andric     return makeConstantsWithType(Cur[1]->getType());
22906c3fb27SDimitry Andric   };
23006c3fb27SDimitry Andric   return {Pred, Make};
23106c3fb27SDimitry Andric }
23206c3fb27SDimitry Andric 
anyAggregateType()2330b57cec5SDimitry Andric static inline SourcePred anyAggregateType() {
2340b57cec5SDimitry Andric   auto Pred = [](ArrayRef<Value *>, const Value *V) {
2350b57cec5SDimitry Andric     // We can't index zero sized arrays.
2360b57cec5SDimitry Andric     if (isa<ArrayType>(V->getType()))
2370b57cec5SDimitry Andric       return V->getType()->getArrayNumElements() > 0;
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric     // Structs can also be zero sized. I.e opaque types.
2400b57cec5SDimitry Andric     if (isa<StructType>(V->getType()))
2410b57cec5SDimitry Andric       return V->getType()->getStructNumElements() > 0;
2420b57cec5SDimitry Andric 
2430b57cec5SDimitry Andric     return V->getType()->isAggregateType();
2440b57cec5SDimitry Andric   };
2450b57cec5SDimitry Andric   // TODO: For now we only find aggregates in BaseTypes. It might be better to
2460b57cec5SDimitry Andric   // manufacture them out of the base types in some cases.
247bdd1243dSDimitry Andric   auto Find = std::nullopt;
2480b57cec5SDimitry Andric   return {Pred, Find};
2490b57cec5SDimitry Andric }
2500b57cec5SDimitry Andric 
anyVectorType()2510b57cec5SDimitry Andric static inline SourcePred anyVectorType() {
2520b57cec5SDimitry Andric   auto Pred = [](ArrayRef<Value *>, const Value *V) {
2530b57cec5SDimitry Andric     return V->getType()->isVectorTy();
2540b57cec5SDimitry Andric   };
2550b57cec5SDimitry Andric   // TODO: For now we only find vectors in BaseTypes. It might be better to
2560b57cec5SDimitry Andric   // manufacture vectors out of the base types, but it's tricky to be sure
2570b57cec5SDimitry Andric   // that's actually a reasonable type.
258bdd1243dSDimitry Andric   auto Make = std::nullopt;
2590b57cec5SDimitry Andric   return {Pred, Make};
2600b57cec5SDimitry Andric }
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric /// Match values that have the same type as the first source.
matchFirstType()2630b57cec5SDimitry Andric static inline SourcePred matchFirstType() {
2640b57cec5SDimitry Andric   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
2650b57cec5SDimitry Andric     assert(!Cur.empty() && "No first source yet");
2660b57cec5SDimitry Andric     return V->getType() == Cur[0]->getType();
2670b57cec5SDimitry Andric   };
2680b57cec5SDimitry Andric   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
2690b57cec5SDimitry Andric     assert(!Cur.empty() && "No first source yet");
2700b57cec5SDimitry Andric     return makeConstantsWithType(Cur[0]->getType());
2710b57cec5SDimitry Andric   };
2720b57cec5SDimitry Andric   return {Pred, Make};
2730b57cec5SDimitry Andric }
2740b57cec5SDimitry Andric 
2750b57cec5SDimitry Andric /// Match values that have the first source's scalar type.
matchScalarOfFirstType()2760b57cec5SDimitry Andric static inline SourcePred matchScalarOfFirstType() {
2770b57cec5SDimitry Andric   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
2780b57cec5SDimitry Andric     assert(!Cur.empty() && "No first source yet");
2790b57cec5SDimitry Andric     return V->getType() == Cur[0]->getType()->getScalarType();
2800b57cec5SDimitry Andric   };
2810b57cec5SDimitry Andric   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
2820b57cec5SDimitry Andric     assert(!Cur.empty() && "No first source yet");
2830b57cec5SDimitry Andric     return makeConstantsWithType(Cur[0]->getType()->getScalarType());
2840b57cec5SDimitry Andric   };
2850b57cec5SDimitry Andric   return {Pred, Make};
2860b57cec5SDimitry Andric }
2870b57cec5SDimitry Andric 
288bdd1243dSDimitry Andric } // namespace fuzzerop
289bdd1243dSDimitry Andric } // namespace llvm
2900b57cec5SDimitry Andric 
2910b57cec5SDimitry Andric #endif // LLVM_FUZZMUTATE_OPDESCRIPTOR_H
292