xref: /freebsd/contrib/llvm-project/llvm/lib/FuzzMutate/Operations.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric //===-- Operations.cpp ----------------------------------------------------===//
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 #include "llvm/FuzzMutate/Operations.h"
100b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h"
110b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
120b57cec5SDimitry Andric #include "llvm/IR/Function.h"
130b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric using namespace llvm;
160b57cec5SDimitry Andric using namespace fuzzerop;
170b57cec5SDimitry Andric 
describeFuzzerIntOps(std::vector<fuzzerop::OpDescriptor> & Ops)180b57cec5SDimitry Andric void llvm::describeFuzzerIntOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
190b57cec5SDimitry Andric   Ops.push_back(binOpDescriptor(1, Instruction::Add));
200b57cec5SDimitry Andric   Ops.push_back(binOpDescriptor(1, Instruction::Sub));
210b57cec5SDimitry Andric   Ops.push_back(binOpDescriptor(1, Instruction::Mul));
220b57cec5SDimitry Andric   Ops.push_back(binOpDescriptor(1, Instruction::SDiv));
230b57cec5SDimitry Andric   Ops.push_back(binOpDescriptor(1, Instruction::UDiv));
240b57cec5SDimitry Andric   Ops.push_back(binOpDescriptor(1, Instruction::SRem));
250b57cec5SDimitry Andric   Ops.push_back(binOpDescriptor(1, Instruction::URem));
260b57cec5SDimitry Andric   Ops.push_back(binOpDescriptor(1, Instruction::Shl));
270b57cec5SDimitry Andric   Ops.push_back(binOpDescriptor(1, Instruction::LShr));
280b57cec5SDimitry Andric   Ops.push_back(binOpDescriptor(1, Instruction::AShr));
290b57cec5SDimitry Andric   Ops.push_back(binOpDescriptor(1, Instruction::And));
300b57cec5SDimitry Andric   Ops.push_back(binOpDescriptor(1, Instruction::Or));
310b57cec5SDimitry Andric   Ops.push_back(binOpDescriptor(1, Instruction::Xor));
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_EQ));
340b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_NE));
350b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_UGT));
360b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_UGE));
370b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_ULT));
380b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_ULE));
390b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_SGT));
400b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_SGE));
410b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_SLT));
420b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_SLE));
430b57cec5SDimitry Andric }
440b57cec5SDimitry Andric 
describeFuzzerFloatOps(std::vector<fuzzerop::OpDescriptor> & Ops)450b57cec5SDimitry Andric void llvm::describeFuzzerFloatOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
460b57cec5SDimitry Andric   Ops.push_back(binOpDescriptor(1, Instruction::FAdd));
470b57cec5SDimitry Andric   Ops.push_back(binOpDescriptor(1, Instruction::FSub));
480b57cec5SDimitry Andric   Ops.push_back(binOpDescriptor(1, Instruction::FMul));
490b57cec5SDimitry Andric   Ops.push_back(binOpDescriptor(1, Instruction::FDiv));
500b57cec5SDimitry Andric   Ops.push_back(binOpDescriptor(1, Instruction::FRem));
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_FALSE));
530b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OEQ));
540b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OGT));
550b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OGE));
560b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OLT));
570b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OLE));
580b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_ONE));
590b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_ORD));
600b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UNO));
610b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UEQ));
620b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UGT));
630b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UGE));
640b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_ULT));
650b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_ULE));
660b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UNE));
670b57cec5SDimitry Andric   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_TRUE));
680b57cec5SDimitry Andric }
690b57cec5SDimitry Andric 
describeFuzzerUnaryOperations(std::vector<fuzzerop::OpDescriptor> & Ops)70*06c3fb27SDimitry Andric void llvm::describeFuzzerUnaryOperations(
71*06c3fb27SDimitry Andric     std::vector<fuzzerop::OpDescriptor> &Ops) {
72*06c3fb27SDimitry Andric   Ops.push_back(fnegDescriptor(1));
73*06c3fb27SDimitry Andric }
74*06c3fb27SDimitry Andric 
describeFuzzerControlFlowOps(std::vector<fuzzerop::OpDescriptor> & Ops)750b57cec5SDimitry Andric void llvm::describeFuzzerControlFlowOps(
760b57cec5SDimitry Andric     std::vector<fuzzerop::OpDescriptor> &Ops) {
770b57cec5SDimitry Andric   Ops.push_back(splitBlockDescriptor(1));
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric 
describeFuzzerOtherOps(std::vector<fuzzerop::OpDescriptor> & Ops)80*06c3fb27SDimitry Andric void llvm::describeFuzzerOtherOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
81*06c3fb27SDimitry Andric   Ops.push_back(selectDescriptor(1));
82*06c3fb27SDimitry Andric }
83*06c3fb27SDimitry Andric 
describeFuzzerPointerOps(std::vector<fuzzerop::OpDescriptor> & Ops)840b57cec5SDimitry Andric void llvm::describeFuzzerPointerOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
850b57cec5SDimitry Andric   Ops.push_back(gepDescriptor(1));
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric 
describeFuzzerAggregateOps(std::vector<fuzzerop::OpDescriptor> & Ops)880b57cec5SDimitry Andric void llvm::describeFuzzerAggregateOps(
890b57cec5SDimitry Andric     std::vector<fuzzerop::OpDescriptor> &Ops) {
900b57cec5SDimitry Andric   Ops.push_back(extractValueDescriptor(1));
910b57cec5SDimitry Andric   Ops.push_back(insertValueDescriptor(1));
920b57cec5SDimitry Andric }
930b57cec5SDimitry Andric 
describeFuzzerVectorOps(std::vector<fuzzerop::OpDescriptor> & Ops)940b57cec5SDimitry Andric void llvm::describeFuzzerVectorOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
950b57cec5SDimitry Andric   Ops.push_back(extractElementDescriptor(1));
960b57cec5SDimitry Andric   Ops.push_back(insertElementDescriptor(1));
970b57cec5SDimitry Andric   Ops.push_back(shuffleVectorDescriptor(1));
980b57cec5SDimitry Andric }
990b57cec5SDimitry Andric 
selectDescriptor(unsigned Weight)100*06c3fb27SDimitry Andric OpDescriptor llvm::fuzzerop::selectDescriptor(unsigned Weight) {
101*06c3fb27SDimitry Andric   auto buildOp = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
102*06c3fb27SDimitry Andric     return SelectInst::Create(Srcs[0], Srcs[1], Srcs[2], "S", Inst);
103*06c3fb27SDimitry Andric   };
104*06c3fb27SDimitry Andric   return {Weight,
105*06c3fb27SDimitry Andric           {boolOrVecBoolType(), matchFirstLengthWAnyType(), matchSecondType()},
106*06c3fb27SDimitry Andric           buildOp};
107*06c3fb27SDimitry Andric }
108*06c3fb27SDimitry Andric 
fnegDescriptor(unsigned Weight)109*06c3fb27SDimitry Andric OpDescriptor llvm::fuzzerop::fnegDescriptor(unsigned Weight) {
110*06c3fb27SDimitry Andric   auto buildOp = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
111*06c3fb27SDimitry Andric     return UnaryOperator::Create(Instruction::FNeg, Srcs[0], "F", Inst);
112*06c3fb27SDimitry Andric   };
113*06c3fb27SDimitry Andric   return {Weight, {anyFloatOrVecFloatType()}, buildOp};
114*06c3fb27SDimitry Andric }
115*06c3fb27SDimitry Andric 
binOpDescriptor(unsigned Weight,Instruction::BinaryOps Op)1160b57cec5SDimitry Andric OpDescriptor llvm::fuzzerop::binOpDescriptor(unsigned Weight,
1170b57cec5SDimitry Andric                                              Instruction::BinaryOps Op) {
1180b57cec5SDimitry Andric   auto buildOp = [Op](ArrayRef<Value *> Srcs, Instruction *Inst) {
1190b57cec5SDimitry Andric     return BinaryOperator::Create(Op, Srcs[0], Srcs[1], "B", Inst);
1200b57cec5SDimitry Andric   };
1210b57cec5SDimitry Andric   switch (Op) {
1220b57cec5SDimitry Andric   case Instruction::Add:
1230b57cec5SDimitry Andric   case Instruction::Sub:
1240b57cec5SDimitry Andric   case Instruction::Mul:
1250b57cec5SDimitry Andric   case Instruction::SDiv:
1260b57cec5SDimitry Andric   case Instruction::UDiv:
1270b57cec5SDimitry Andric   case Instruction::SRem:
1280b57cec5SDimitry Andric   case Instruction::URem:
1290b57cec5SDimitry Andric   case Instruction::Shl:
1300b57cec5SDimitry Andric   case Instruction::LShr:
1310b57cec5SDimitry Andric   case Instruction::AShr:
1320b57cec5SDimitry Andric   case Instruction::And:
1330b57cec5SDimitry Andric   case Instruction::Or:
1340b57cec5SDimitry Andric   case Instruction::Xor:
135*06c3fb27SDimitry Andric     return {Weight, {anyIntOrVecIntType(), matchFirstType()}, buildOp};
1360b57cec5SDimitry Andric   case Instruction::FAdd:
1370b57cec5SDimitry Andric   case Instruction::FSub:
1380b57cec5SDimitry Andric   case Instruction::FMul:
1390b57cec5SDimitry Andric   case Instruction::FDiv:
1400b57cec5SDimitry Andric   case Instruction::FRem:
141*06c3fb27SDimitry Andric     return {Weight, {anyFloatOrVecFloatType(), matchFirstType()}, buildOp};
1420b57cec5SDimitry Andric   case Instruction::BinaryOpsEnd:
1430b57cec5SDimitry Andric     llvm_unreachable("Value out of range of enum");
1440b57cec5SDimitry Andric   }
1450b57cec5SDimitry Andric   llvm_unreachable("Covered switch");
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric 
cmpOpDescriptor(unsigned Weight,Instruction::OtherOps CmpOp,CmpInst::Predicate Pred)1480b57cec5SDimitry Andric OpDescriptor llvm::fuzzerop::cmpOpDescriptor(unsigned Weight,
1490b57cec5SDimitry Andric                                              Instruction::OtherOps CmpOp,
1500b57cec5SDimitry Andric                                              CmpInst::Predicate Pred) {
1510b57cec5SDimitry Andric   auto buildOp = [CmpOp, Pred](ArrayRef<Value *> Srcs, Instruction *Inst) {
1520b57cec5SDimitry Andric     return CmpInst::Create(CmpOp, Pred, Srcs[0], Srcs[1], "C", Inst);
1530b57cec5SDimitry Andric   };
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric   switch (CmpOp) {
1560b57cec5SDimitry Andric   case Instruction::ICmp:
157*06c3fb27SDimitry Andric     return {Weight, {anyIntOrVecIntType(), matchFirstType()}, buildOp};
1580b57cec5SDimitry Andric   case Instruction::FCmp:
159*06c3fb27SDimitry Andric     return {Weight, {anyFloatOrVecFloatType(), matchFirstType()}, buildOp};
1600b57cec5SDimitry Andric   default:
1610b57cec5SDimitry Andric     llvm_unreachable("CmpOp must be ICmp or FCmp");
1620b57cec5SDimitry Andric   }
1630b57cec5SDimitry Andric }
1640b57cec5SDimitry Andric 
splitBlockDescriptor(unsigned Weight)1650b57cec5SDimitry Andric OpDescriptor llvm::fuzzerop::splitBlockDescriptor(unsigned Weight) {
1660b57cec5SDimitry Andric   auto buildSplitBlock = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
1670b57cec5SDimitry Andric     BasicBlock *Block = Inst->getParent();
1680b57cec5SDimitry Andric     BasicBlock *Next = Block->splitBasicBlock(Inst, "BB");
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric     // If it was an exception handling block, we are done.
1710b57cec5SDimitry Andric     if (Block->isEHPad())
1720b57cec5SDimitry Andric       return nullptr;
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric     // Loop back on this block by replacing the unconditional forward branch
1750b57cec5SDimitry Andric     // with a conditional with a backedge.
1760b57cec5SDimitry Andric     if (Block != &Block->getParent()->getEntryBlock()) {
1770b57cec5SDimitry Andric       BranchInst::Create(Block, Next, Srcs[0], Block->getTerminator());
1780b57cec5SDimitry Andric       Block->getTerminator()->eraseFromParent();
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric       // We need values for each phi in the block. Since there isn't a good way
1810b57cec5SDimitry Andric       // to do a variable number of input values currently, we just fill them
1820b57cec5SDimitry Andric       // with undef.
1830b57cec5SDimitry Andric       for (PHINode &PHI : Block->phis())
1840b57cec5SDimitry Andric         PHI.addIncoming(UndefValue::get(PHI.getType()), Block);
1850b57cec5SDimitry Andric     }
1860b57cec5SDimitry Andric     return nullptr;
1870b57cec5SDimitry Andric   };
1880b57cec5SDimitry Andric   SourcePred isInt1Ty{[](ArrayRef<Value *>, const Value *V) {
1890b57cec5SDimitry Andric                         return V->getType()->isIntegerTy(1);
1900b57cec5SDimitry Andric                       },
191bdd1243dSDimitry Andric                       std::nullopt};
1920b57cec5SDimitry Andric   return {Weight, {isInt1Ty}, buildSplitBlock};
1930b57cec5SDimitry Andric }
1940b57cec5SDimitry Andric 
gepDescriptor(unsigned Weight)1950b57cec5SDimitry Andric OpDescriptor llvm::fuzzerop::gepDescriptor(unsigned Weight) {
1960b57cec5SDimitry Andric   auto buildGEP = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
19781ad6265SDimitry Andric     // TODO: It would be better to generate a random type here, rather than
19881ad6265SDimitry Andric     // generating a random value and picking its type.
199*06c3fb27SDimitry Andric     Type *Ty = Srcs[1]->getType();
200bdd1243dSDimitry Andric     auto Indices = ArrayRef(Srcs).drop_front(2);
2010b57cec5SDimitry Andric     return GetElementPtrInst::Create(Ty, Srcs[0], Indices, "G", Inst);
2020b57cec5SDimitry Andric   };
2030b57cec5SDimitry Andric   // TODO: Handle aggregates and vectors
2040b57cec5SDimitry Andric   // TODO: Support multiple indices.
2050b57cec5SDimitry Andric   // TODO: Try to avoid meaningless accesses.
20681ad6265SDimitry Andric   SourcePred sizedType(
20781ad6265SDimitry Andric       [](ArrayRef<Value *>, const Value *V) { return V->getType()->isSized(); },
208bdd1243dSDimitry Andric       std::nullopt);
20981ad6265SDimitry Andric   return {Weight, {sizedPtrType(), sizedType, anyIntType()}, buildGEP};
2100b57cec5SDimitry Andric }
2110b57cec5SDimitry Andric 
getAggregateNumElements(Type * T)2120b57cec5SDimitry Andric static uint64_t getAggregateNumElements(Type *T) {
2130b57cec5SDimitry Andric   assert(T->isAggregateType() && "Not a struct or array");
2140b57cec5SDimitry Andric   if (isa<StructType>(T))
2150b57cec5SDimitry Andric     return T->getStructNumElements();
2160b57cec5SDimitry Andric   return T->getArrayNumElements();
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric 
validExtractValueIndex()2190b57cec5SDimitry Andric static SourcePred validExtractValueIndex() {
2200b57cec5SDimitry Andric   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
2210b57cec5SDimitry Andric     if (auto *CI = dyn_cast<ConstantInt>(V))
2220b57cec5SDimitry Andric       if (!CI->uge(getAggregateNumElements(Cur[0]->getType())))
2230b57cec5SDimitry Andric         return true;
2240b57cec5SDimitry Andric     return false;
2250b57cec5SDimitry Andric   };
2260b57cec5SDimitry Andric   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> Ts) {
2270b57cec5SDimitry Andric     std::vector<Constant *> Result;
2280b57cec5SDimitry Andric     auto *Int32Ty = Type::getInt32Ty(Cur[0]->getContext());
2290b57cec5SDimitry Andric     uint64_t N = getAggregateNumElements(Cur[0]->getType());
2300b57cec5SDimitry Andric     // Create indices at the start, end, and middle, but avoid dups.
2310b57cec5SDimitry Andric     Result.push_back(ConstantInt::get(Int32Ty, 0));
2320b57cec5SDimitry Andric     if (N > 1)
2330b57cec5SDimitry Andric       Result.push_back(ConstantInt::get(Int32Ty, N - 1));
2340b57cec5SDimitry Andric     if (N > 2)
2350b57cec5SDimitry Andric       Result.push_back(ConstantInt::get(Int32Ty, N / 2));
2360b57cec5SDimitry Andric     return Result;
2370b57cec5SDimitry Andric   };
2380b57cec5SDimitry Andric   return {Pred, Make};
2390b57cec5SDimitry Andric }
2400b57cec5SDimitry Andric 
extractValueDescriptor(unsigned Weight)2410b57cec5SDimitry Andric OpDescriptor llvm::fuzzerop::extractValueDescriptor(unsigned Weight) {
2420b57cec5SDimitry Andric   auto buildExtract = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
2430b57cec5SDimitry Andric     // TODO: It's pretty inefficient to shuffle this all through constants.
2440b57cec5SDimitry Andric     unsigned Idx = cast<ConstantInt>(Srcs[1])->getZExtValue();
2450b57cec5SDimitry Andric     return ExtractValueInst::Create(Srcs[0], {Idx}, "E", Inst);
2460b57cec5SDimitry Andric   };
2470b57cec5SDimitry Andric   // TODO: Should we handle multiple indices?
2480b57cec5SDimitry Andric   return {Weight, {anyAggregateType(), validExtractValueIndex()}, buildExtract};
2490b57cec5SDimitry Andric }
2500b57cec5SDimitry Andric 
matchScalarInAggregate()2510b57cec5SDimitry Andric static SourcePred matchScalarInAggregate() {
2520b57cec5SDimitry Andric   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
2530b57cec5SDimitry Andric     if (auto *ArrayT = dyn_cast<ArrayType>(Cur[0]->getType()))
2540b57cec5SDimitry Andric       return V->getType() == ArrayT->getElementType();
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric     auto *STy = cast<StructType>(Cur[0]->getType());
2570b57cec5SDimitry Andric     for (int I = 0, E = STy->getNumElements(); I < E; ++I)
2580b57cec5SDimitry Andric       if (STy->getTypeAtIndex(I) == V->getType())
2590b57cec5SDimitry Andric         return true;
2600b57cec5SDimitry Andric     return false;
2610b57cec5SDimitry Andric   };
2620b57cec5SDimitry Andric   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
2630b57cec5SDimitry Andric     if (auto *ArrayT = dyn_cast<ArrayType>(Cur[0]->getType()))
2640b57cec5SDimitry Andric       return makeConstantsWithType(ArrayT->getElementType());
2650b57cec5SDimitry Andric 
2660b57cec5SDimitry Andric     std::vector<Constant *> Result;
2670b57cec5SDimitry Andric     auto *STy = cast<StructType>(Cur[0]->getType());
2680b57cec5SDimitry Andric     for (int I = 0, E = STy->getNumElements(); I < E; ++I)
2690b57cec5SDimitry Andric       makeConstantsWithType(STy->getTypeAtIndex(I), Result);
2700b57cec5SDimitry Andric     return Result;
2710b57cec5SDimitry Andric   };
2720b57cec5SDimitry Andric   return {Pred, Make};
2730b57cec5SDimitry Andric }
2740b57cec5SDimitry Andric 
validInsertValueIndex()2750b57cec5SDimitry Andric static SourcePred validInsertValueIndex() {
2760b57cec5SDimitry Andric   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
2770b57cec5SDimitry Andric     if (auto *CI = dyn_cast<ConstantInt>(V))
2785ffd83dbSDimitry Andric       if (CI->getBitWidth() == 32) {
2795ffd83dbSDimitry Andric         Type *Indexed = ExtractValueInst::getIndexedType(Cur[0]->getType(),
2805ffd83dbSDimitry Andric                                                          CI->getZExtValue());
2815ffd83dbSDimitry Andric         return Indexed == Cur[1]->getType();
2825ffd83dbSDimitry Andric       }
2830b57cec5SDimitry Andric     return false;
2840b57cec5SDimitry Andric   };
2850b57cec5SDimitry Andric   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> Ts) {
2860b57cec5SDimitry Andric     std::vector<Constant *> Result;
2870b57cec5SDimitry Andric     auto *Int32Ty = Type::getInt32Ty(Cur[0]->getContext());
2885ffd83dbSDimitry Andric     auto *BaseTy = Cur[0]->getType();
2895ffd83dbSDimitry Andric     int I = 0;
2905ffd83dbSDimitry Andric     while (Type *Indexed = ExtractValueInst::getIndexedType(BaseTy, I)) {
2915ffd83dbSDimitry Andric       if (Indexed == Cur[1]->getType())
2920b57cec5SDimitry Andric         Result.push_back(ConstantInt::get(Int32Ty, I));
2935ffd83dbSDimitry Andric       ++I;
2945ffd83dbSDimitry Andric     }
2950b57cec5SDimitry Andric     return Result;
2960b57cec5SDimitry Andric   };
2970b57cec5SDimitry Andric   return {Pred, Make};
2980b57cec5SDimitry Andric }
2990b57cec5SDimitry Andric 
insertValueDescriptor(unsigned Weight)3000b57cec5SDimitry Andric OpDescriptor llvm::fuzzerop::insertValueDescriptor(unsigned Weight) {
3010b57cec5SDimitry Andric   auto buildInsert = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
3020b57cec5SDimitry Andric     // TODO: It's pretty inefficient to shuffle this all through constants.
3030b57cec5SDimitry Andric     unsigned Idx = cast<ConstantInt>(Srcs[2])->getZExtValue();
3040b57cec5SDimitry Andric     return InsertValueInst::Create(Srcs[0], Srcs[1], {Idx}, "I", Inst);
3050b57cec5SDimitry Andric   };
3060b57cec5SDimitry Andric   return {
3070b57cec5SDimitry Andric       Weight,
3080b57cec5SDimitry Andric       {anyAggregateType(), matchScalarInAggregate(), validInsertValueIndex()},
3090b57cec5SDimitry Andric       buildInsert};
3100b57cec5SDimitry Andric }
3110b57cec5SDimitry Andric 
extractElementDescriptor(unsigned Weight)3120b57cec5SDimitry Andric OpDescriptor llvm::fuzzerop::extractElementDescriptor(unsigned Weight) {
3130b57cec5SDimitry Andric   auto buildExtract = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
3140b57cec5SDimitry Andric     return ExtractElementInst::Create(Srcs[0], Srcs[1], "E", Inst);
3150b57cec5SDimitry Andric   };
3160b57cec5SDimitry Andric   // TODO: Try to avoid undefined accesses.
3170b57cec5SDimitry Andric   return {Weight, {anyVectorType(), anyIntType()}, buildExtract};
3180b57cec5SDimitry Andric }
3190b57cec5SDimitry Andric 
insertElementDescriptor(unsigned Weight)3200b57cec5SDimitry Andric OpDescriptor llvm::fuzzerop::insertElementDescriptor(unsigned Weight) {
3210b57cec5SDimitry Andric   auto buildInsert = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
3220b57cec5SDimitry Andric     return InsertElementInst::Create(Srcs[0], Srcs[1], Srcs[2], "I", Inst);
3230b57cec5SDimitry Andric   };
3240b57cec5SDimitry Andric   // TODO: Try to avoid undefined accesses.
3250b57cec5SDimitry Andric   return {Weight,
3260b57cec5SDimitry Andric           {anyVectorType(), matchScalarOfFirstType(), anyIntType()},
3270b57cec5SDimitry Andric           buildInsert};
3280b57cec5SDimitry Andric }
3290b57cec5SDimitry Andric 
validShuffleVectorIndex()3300b57cec5SDimitry Andric static SourcePred validShuffleVectorIndex() {
3310b57cec5SDimitry Andric   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
3320b57cec5SDimitry Andric     return ShuffleVectorInst::isValidOperands(Cur[0], Cur[1], V);
3330b57cec5SDimitry Andric   };
3340b57cec5SDimitry Andric   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> Ts) {
33581ad6265SDimitry Andric     auto *FirstTy = cast<VectorType>(Cur[0]->getType());
3360b57cec5SDimitry Andric     auto *Int32Ty = Type::getInt32Ty(Cur[0]->getContext());
3370b57cec5SDimitry Andric     // TODO: It's straighforward to make up reasonable values, but listing them
3380b57cec5SDimitry Andric     // exhaustively would be insane. Come up with a couple of sensible ones.
339bdd1243dSDimitry Andric     return std::vector<Constant *>{
340bdd1243dSDimitry Andric         UndefValue::get(VectorType::get(Int32Ty, FirstTy->getElementCount()))};
3410b57cec5SDimitry Andric   };
3420b57cec5SDimitry Andric   return {Pred, Make};
3430b57cec5SDimitry Andric }
3440b57cec5SDimitry Andric 
shuffleVectorDescriptor(unsigned Weight)3450b57cec5SDimitry Andric OpDescriptor llvm::fuzzerop::shuffleVectorDescriptor(unsigned Weight) {
3460b57cec5SDimitry Andric   auto buildShuffle = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
3470b57cec5SDimitry Andric     return new ShuffleVectorInst(Srcs[0], Srcs[1], Srcs[2], "S", Inst);
3480b57cec5SDimitry Andric   };
3490b57cec5SDimitry Andric   return {Weight,
3500b57cec5SDimitry Andric           {anyVectorType(), matchFirstType(), validShuffleVectorIndex()},
3510b57cec5SDimitry Andric           buildShuffle};
3520b57cec5SDimitry Andric }
353