1326938Sdim//===-- OpDescriptor.h ------------------------------------------*- C++ -*-===// 2326938Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6326938Sdim// 7326938Sdim//===----------------------------------------------------------------------===// 8326938Sdim// 9326938Sdim// Provides the fuzzerop::Descriptor class and related tools for describing 10326938Sdim// operations an IR fuzzer can work with. 11326938Sdim// 12326938Sdim//===----------------------------------------------------------------------===// 13326938Sdim 14326938Sdim#ifndef LLVM_FUZZMUTATE_OPDESCRIPTOR_H 15326938Sdim#define LLVM_FUZZMUTATE_OPDESCRIPTOR_H 16326938Sdim 17326938Sdim#include "llvm/ADT/ArrayRef.h" 18326938Sdim#include "llvm/ADT/STLExtras.h" 19326938Sdim#include "llvm/ADT/SmallVector.h" 20326938Sdim#include "llvm/IR/Constants.h" 21326938Sdim#include "llvm/IR/DerivedTypes.h" 22341825Sdim#include "llvm/IR/Instructions.h" 23326938Sdim#include "llvm/IR/Type.h" 24326938Sdim#include "llvm/IR/Value.h" 25326938Sdim#include <functional> 26326938Sdim 27326938Sdimnamespace llvm { 28326938Sdimnamespace fuzzerop { 29326938Sdim 30326938Sdim/// @{ 31326938Sdim/// Populate a small list of potentially interesting constants of a given type. 32326938Sdimvoid makeConstantsWithType(Type *T, std::vector<Constant *> &Cs); 33326938Sdimstd::vector<Constant *> makeConstantsWithType(Type *T); 34326938Sdim/// @} 35326938Sdim 36326938Sdim/// A matcher/generator for finding suitable values for the next source in an 37326938Sdim/// operation's partially completed argument list. 38326938Sdim/// 39326938Sdim/// Given that we're building some operation X and may have already filled some 40326938Sdim/// subset of its operands, this predicate determines if some value New is 41326938Sdim/// suitable for the next operand or generates a set of values that are 42326938Sdim/// suitable. 43326938Sdimclass SourcePred { 44326938Sdimpublic: 45326938Sdim /// Given a list of already selected operands, returns whether a given new 46326938Sdim /// operand is suitable for the next operand. 47326938Sdim using PredT = std::function<bool(ArrayRef<Value *> Cur, const Value *New)>; 48326938Sdim /// Given a list of already selected operands and a set of valid base types 49326938Sdim /// for a fuzzer, generates a list of constants that could be used for the 50326938Sdim /// next operand. 51326938Sdim using MakeT = std::function<std::vector<Constant *>( 52326938Sdim ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes)>; 53326938Sdim 54326938Sdimprivate: 55326938Sdim PredT Pred; 56326938Sdim MakeT Make; 57326938Sdim 58326938Sdimpublic: 59326938Sdim /// Create a fully general source predicate. 60326938Sdim SourcePred(PredT Pred, MakeT Make) : Pred(Pred), Make(Make) {} 61326938Sdim SourcePred(PredT Pred, NoneType) : Pred(Pred) { 62326938Sdim Make = [Pred](ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes) { 63326938Sdim // Default filter just calls Pred on each of the base types. 64326938Sdim std::vector<Constant *> Result; 65326938Sdim for (Type *T : BaseTypes) { 66326938Sdim Constant *V = UndefValue::get(T); 67326938Sdim if (Pred(Cur, V)) 68326938Sdim makeConstantsWithType(T, Result); 69326938Sdim } 70326938Sdim if (Result.empty()) 71326938Sdim report_fatal_error("Predicate does not match for base types"); 72326938Sdim return Result; 73326938Sdim }; 74326938Sdim } 75326938Sdim 76326938Sdim /// Returns true if \c New is compatible for the argument after \c Cur 77326938Sdim bool matches(ArrayRef<Value *> Cur, const Value *New) { 78326938Sdim return Pred(Cur, New); 79326938Sdim } 80326938Sdim 81326938Sdim /// Generates a list of potential values for the argument after \c Cur. 82326938Sdim std::vector<Constant *> generate(ArrayRef<Value *> Cur, 83326938Sdim ArrayRef<Type *> BaseTypes) { 84326938Sdim return Make(Cur, BaseTypes); 85326938Sdim } 86326938Sdim}; 87326938Sdim 88326938Sdim/// A description of some operation we can build while fuzzing IR. 89326938Sdimstruct OpDescriptor { 90326938Sdim unsigned Weight; 91326938Sdim SmallVector<SourcePred, 2> SourcePreds; 92326938Sdim std::function<Value *(ArrayRef<Value *>, Instruction *)> BuilderFunc; 93326938Sdim}; 94326938Sdim 95326938Sdimstatic inline SourcePred onlyType(Type *Only) { 96326938Sdim auto Pred = [Only](ArrayRef<Value *>, const Value *V) { 97326938Sdim return V->getType() == Only; 98326938Sdim }; 99326938Sdim auto Make = [Only](ArrayRef<Value *>, ArrayRef<Type *>) { 100326938Sdim return makeConstantsWithType(Only); 101326938Sdim }; 102326938Sdim return {Pred, Make}; 103326938Sdim} 104326938Sdim 105326938Sdimstatic inline SourcePred anyType() { 106326938Sdim auto Pred = [](ArrayRef<Value *>, const Value *V) { 107326938Sdim return !V->getType()->isVoidTy(); 108326938Sdim }; 109326938Sdim auto Make = None; 110326938Sdim return {Pred, Make}; 111326938Sdim} 112326938Sdim 113326938Sdimstatic inline SourcePred anyIntType() { 114326938Sdim auto Pred = [](ArrayRef<Value *>, const Value *V) { 115326938Sdim return V->getType()->isIntegerTy(); 116326938Sdim }; 117326938Sdim auto Make = None; 118326938Sdim return {Pred, Make}; 119326938Sdim} 120326938Sdim 121326938Sdimstatic inline SourcePred anyFloatType() { 122326938Sdim auto Pred = [](ArrayRef<Value *>, const Value *V) { 123326938Sdim return V->getType()->isFloatingPointTy(); 124326938Sdim }; 125326938Sdim auto Make = None; 126326938Sdim return {Pred, Make}; 127326938Sdim} 128326938Sdim 129326938Sdimstatic inline SourcePred anyPtrType() { 130326938Sdim auto Pred = [](ArrayRef<Value *>, const Value *V) { 131341825Sdim return V->getType()->isPointerTy() && !V->isSwiftError(); 132326938Sdim }; 133326938Sdim auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) { 134326938Sdim std::vector<Constant *> Result; 135326938Sdim // TODO: Should these point at something? 136326938Sdim for (Type *T : Ts) 137326938Sdim Result.push_back(UndefValue::get(PointerType::getUnqual(T))); 138326938Sdim return Result; 139326938Sdim }; 140326938Sdim return {Pred, Make}; 141326938Sdim} 142326938Sdim 143326938Sdimstatic inline SourcePred sizedPtrType() { 144326938Sdim auto Pred = [](ArrayRef<Value *>, const Value *V) { 145341825Sdim if (V->isSwiftError()) 146341825Sdim return false; 147341825Sdim 148326938Sdim if (const auto *PtrT = dyn_cast<PointerType>(V->getType())) 149326938Sdim return PtrT->getElementType()->isSized(); 150326938Sdim return false; 151326938Sdim }; 152326938Sdim auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) { 153326938Sdim std::vector<Constant *> Result; 154326938Sdim 155326938Sdim for (Type *T : Ts) 156326938Sdim if (T->isSized()) 157326938Sdim Result.push_back(UndefValue::get(PointerType::getUnqual(T))); 158326938Sdim 159326938Sdim return Result; 160326938Sdim }; 161326938Sdim return {Pred, Make}; 162326938Sdim} 163326938Sdim 164326938Sdimstatic inline SourcePred anyAggregateType() { 165326938Sdim auto Pred = [](ArrayRef<Value *>, const Value *V) { 166326938Sdim // We can't index zero sized arrays. 167326938Sdim if (isa<ArrayType>(V->getType())) 168326938Sdim return V->getType()->getArrayNumElements() > 0; 169326938Sdim 170326938Sdim // Structs can also be zero sized. I.e opaque types. 171326938Sdim if (isa<StructType>(V->getType())) 172326938Sdim return V->getType()->getStructNumElements() > 0; 173326938Sdim 174326938Sdim return V->getType()->isAggregateType(); 175326938Sdim }; 176326938Sdim // TODO: For now we only find aggregates in BaseTypes. It might be better to 177326938Sdim // manufacture them out of the base types in some cases. 178326938Sdim auto Find = None; 179326938Sdim return {Pred, Find}; 180326938Sdim} 181326938Sdim 182326938Sdimstatic inline SourcePred anyVectorType() { 183326938Sdim auto Pred = [](ArrayRef<Value *>, const Value *V) { 184326938Sdim return V->getType()->isVectorTy(); 185326938Sdim }; 186326938Sdim // TODO: For now we only find vectors in BaseTypes. It might be better to 187326938Sdim // manufacture vectors out of the base types, but it's tricky to be sure 188326938Sdim // that's actually a reasonable type. 189326938Sdim auto Make = None; 190326938Sdim return {Pred, Make}; 191326938Sdim} 192326938Sdim 193326938Sdim/// Match values that have the same type as the first source. 194326938Sdimstatic inline SourcePred matchFirstType() { 195326938Sdim auto Pred = [](ArrayRef<Value *> Cur, const Value *V) { 196326938Sdim assert(!Cur.empty() && "No first source yet"); 197326938Sdim return V->getType() == Cur[0]->getType(); 198326938Sdim }; 199326938Sdim auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) { 200326938Sdim assert(!Cur.empty() && "No first source yet"); 201326938Sdim return makeConstantsWithType(Cur[0]->getType()); 202326938Sdim }; 203326938Sdim return {Pred, Make}; 204326938Sdim} 205326938Sdim 206326938Sdim/// Match values that have the first source's scalar type. 207326938Sdimstatic inline SourcePred matchScalarOfFirstType() { 208326938Sdim auto Pred = [](ArrayRef<Value *> Cur, const Value *V) { 209326938Sdim assert(!Cur.empty() && "No first source yet"); 210326938Sdim return V->getType() == Cur[0]->getType()->getScalarType(); 211326938Sdim }; 212326938Sdim auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) { 213326938Sdim assert(!Cur.empty() && "No first source yet"); 214326938Sdim return makeConstantsWithType(Cur[0]->getType()->getScalarType()); 215326938Sdim }; 216326938Sdim return {Pred, Make}; 217326938Sdim} 218326938Sdim 219326938Sdim} // end fuzzerop namespace 220326938Sdim} // end llvm namespace 221326938Sdim 222326938Sdim#endif // LLVM_FUZZMUTATE_OPDESCRIPTOR_H 223