//===-- OpDescriptor.h ------------------------------------------*- C++ -*-===//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
//
 
// Provides the fuzzerop::Descriptor class and related tools for describing
 
// operations an IR fuzzer can work with.
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_FUZZMUTATE_OPDESCRIPTOR_H
 
#define LLVM_FUZZMUTATE_OPDESCRIPTOR_H
 
 
 
#include "llvm/ADT/ArrayRef.h"
 
#include "llvm/ADT/SmallVector.h"
 
#include "llvm/IR/Constants.h"
 
#include "llvm/IR/DerivedTypes.h"
 
#include "llvm/IR/Type.h"
 
#include "llvm/IR/Value.h"
 
#include <functional>
 
 
 
namespace llvm {
 
class Instruction;
 
namespace fuzzerop {
 
 
 
/// @{
 
/// Populate a small list of potentially interesting constants of a given type.
 
void makeConstantsWithType(Type *T, std::vector<Constant *> &Cs);
 
std::vector<Constant *> makeConstantsWithType(Type *T);
 
/// @}
 
 
 
/// A matcher/generator for finding suitable values for the next source in an
 
/// operation's partially completed argument list.
 
///
 
/// Given that we're building some operation X and may have already filled some
 
/// subset of its operands, this predicate determines if some value New is
 
/// suitable for the next operand or generates a set of values that are
 
/// suitable.
 
class SourcePred {
 
public:
 
  /// Given a list of already selected operands, returns whether a given new
 
  /// operand is suitable for the next operand.
 
  using PredT = std::function<bool(ArrayRef<Value *> Cur, const Value *New)>;
 
  /// Given a list of already selected operands and a set of valid base types
 
  /// for a fuzzer, generates a list of constants that could be used for the
 
  /// next operand.
 
  using MakeT = std::function<std::vector<Constant *>(
 
      ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes)>;
 
 
 
private:
 
  PredT Pred;
 
  MakeT Make;
 
 
 
public:
 
  /// Create a fully general source predicate.
 
  SourcePred(PredT Pred, MakeT Make) : Pred(Pred), Make(Make) {}
 
  SourcePred(PredT Pred, std::nullopt_t) : Pred(Pred) {
 
    Make = [Pred](ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes) {
 
      // Default filter just calls Pred on each of the base types.
 
      std::vector<Constant *> Result;
 
      for (Type *T : BaseTypes) {
 
        Constant *V = UndefValue::get(T);
 
        if (Pred(Cur, V))
 
          makeConstantsWithType(T, Result);
 
      }
 
      if (Result.empty())
 
        report_fatal_error("Predicate does not match for base types");
 
      return Result;
 
    };
 
  }
 
 
 
  /// Returns true if \c New is compatible for the argument after \c Cur
 
  bool matches(ArrayRef<Value *> Cur, const Value *New) {
 
    return Pred(Cur, New);
 
  }
 
 
 
  /// Generates a list of potential values for the argument after \c Cur.
 
  std::vector<Constant *> generate(ArrayRef<Value *> Cur,
 
                                   ArrayRef<Type *> BaseTypes) {
 
    return Make(Cur, BaseTypes);
 
  }
 
};
 
 
 
/// A description of some operation we can build while fuzzing IR.
 
struct OpDescriptor {
 
  unsigned Weight;
 
  SmallVector<SourcePred, 2> SourcePreds;
 
  std::function<Value *(ArrayRef<Value *>, Instruction *)> BuilderFunc;
 
};
 
 
 
static inline SourcePred onlyType(Type *Only) {
 
  auto Pred = [Only](ArrayRef<Value *>, const Value *V) {
 
    return V->getType() == Only;
 
  };
 
  auto Make = [Only](ArrayRef<Value *>, ArrayRef<Type *>) {
 
    return makeConstantsWithType(Only);
 
  };
 
  return {Pred, Make};
 
}
 
 
 
static inline SourcePred anyType() {
 
  auto Pred = [](ArrayRef<Value *>, const Value *V) {
 
    return !V->getType()->isVoidTy();
 
  };
 
  auto Make = std::nullopt;
 
  return {Pred, Make};
 
}
 
 
 
static inline SourcePred anyIntType() {
 
  auto Pred = [](ArrayRef<Value *>, const Value *V) {
 
    return V->getType()->isIntegerTy();
 
  };
 
  auto Make = std::nullopt;
 
  return {Pred, Make};
 
}
 
 
 
static inline SourcePred anyFloatType() {
 
  auto Pred = [](ArrayRef<Value *>, const Value *V) {
 
    return V->getType()->isFloatingPointTy();
 
  };
 
  auto Make = std::nullopt;
 
  return {Pred, Make};
 
}
 
 
 
static inline SourcePred anyPtrType() {
 
  auto Pred = [](ArrayRef<Value *>, const Value *V) {
 
    return V->getType()->isPointerTy() && !V->isSwiftError();
 
  };
 
  auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) {
 
    std::vector<Constant *> Result;
 
    // TODO: Should these point at something?
 
    for (Type *T : Ts)
 
      Result.push_back(UndefValue::get(PointerType::getUnqual(T)));
 
    return Result;
 
  };
 
  return {Pred, Make};
 
}
 
 
 
static inline SourcePred sizedPtrType() {
 
  auto Pred = [](ArrayRef<Value *>, const Value *V) {
 
    if (V->isSwiftError())
 
      return false;
 
 
 
    if (const auto *PtrT = dyn_cast<PointerType>(V->getType()))
 
      return PtrT->isOpaque() ||
 
             PtrT->getNonOpaquePointerElementType()->isSized();
 
    return false;
 
  };
 
  auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) {
 
    std::vector<Constant *> Result;
 
 
 
    for (Type *T : Ts)
 
      if (T->isSized())
 
        Result.push_back(UndefValue::get(PointerType::getUnqual(T)));
 
 
 
    return Result;
 
  };
 
  return {Pred, Make};
 
}
 
 
 
static inline SourcePred anyAggregateType() {
 
  auto Pred = [](ArrayRef<Value *>, const Value *V) {
 
    // We can't index zero sized arrays.
 
    if (isa<ArrayType>(V->getType()))
 
      return V->getType()->getArrayNumElements() > 0;
 
 
 
    // Structs can also be zero sized. I.e opaque types.
 
    if (isa<StructType>(V->getType()))
 
      return V->getType()->getStructNumElements() > 0;
 
 
 
    return V->getType()->isAggregateType();
 
  };
 
  // TODO: For now we only find aggregates in BaseTypes. It might be better to
 
  // manufacture them out of the base types in some cases.
 
  auto Find = std::nullopt;
 
  return {Pred, Find};
 
}
 
 
 
static inline SourcePred anyVectorType() {
 
  auto Pred = [](ArrayRef<Value *>, const Value *V) {
 
    return V->getType()->isVectorTy();
 
  };
 
  // TODO: For now we only find vectors in BaseTypes. It might be better to
 
  // manufacture vectors out of the base types, but it's tricky to be sure
 
  // that's actually a reasonable type.
 
  auto Make = std::nullopt;
 
  return {Pred, Make};
 
}
 
 
 
/// Match values that have the same type as the first source.
 
static inline SourcePred matchFirstType() {
 
  auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
 
    assert(!Cur.empty() && "No first source yet");
 
    return V->getType() == Cur[0]->getType();
 
  };
 
  auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
 
    assert(!Cur.empty() && "No first source yet");
 
    return makeConstantsWithType(Cur[0]->getType());
 
  };
 
  return {Pred, Make};
 
}
 
 
 
/// Match values that have the first source's scalar type.
 
static inline SourcePred matchScalarOfFirstType() {
 
  auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
 
    assert(!Cur.empty() && "No first source yet");
 
    return V->getType() == Cur[0]->getType()->getScalarType();
 
  };
 
  auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
 
    assert(!Cur.empty() && "No first source yet");
 
    return makeConstantsWithType(Cur[0]->getType()->getScalarType());
 
  };
 
  return {Pred, Make};
 
}
 
 
 
} // namespace fuzzerop
 
} // namespace llvm
 
 
 
#endif // LLVM_FUZZMUTATE_OPDESCRIPTOR_H