17d449d31SJustin Bogner //===-- Operations.cpp ----------------------------------------------------===//
27d449d31SJustin Bogner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67d449d31SJustin Bogner //
77d449d31SJustin Bogner //===----------------------------------------------------------------------===//
87d449d31SJustin Bogner 
97d449d31SJustin Bogner #include "llvm/FuzzMutate/Operations.h"
107d449d31SJustin Bogner #include "llvm/IR/BasicBlock.h"
117d449d31SJustin Bogner #include "llvm/IR/Constants.h"
127d449d31SJustin Bogner #include "llvm/IR/Function.h"
137d449d31SJustin Bogner #include "llvm/IR/Instructions.h"
147d449d31SJustin Bogner 
157d449d31SJustin Bogner using namespace llvm;
167d449d31SJustin Bogner using namespace fuzzerop;
177d449d31SJustin Bogner 
describeFuzzerIntOps(std::vector<fuzzerop::OpDescriptor> & Ops)187d449d31SJustin Bogner void llvm::describeFuzzerIntOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
197d449d31SJustin Bogner   Ops.push_back(binOpDescriptor(1, Instruction::Add));
207d449d31SJustin Bogner   Ops.push_back(binOpDescriptor(1, Instruction::Sub));
217d449d31SJustin Bogner   Ops.push_back(binOpDescriptor(1, Instruction::Mul));
227d449d31SJustin Bogner   Ops.push_back(binOpDescriptor(1, Instruction::SDiv));
237d449d31SJustin Bogner   Ops.push_back(binOpDescriptor(1, Instruction::UDiv));
247d449d31SJustin Bogner   Ops.push_back(binOpDescriptor(1, Instruction::SRem));
257d449d31SJustin Bogner   Ops.push_back(binOpDescriptor(1, Instruction::URem));
267d449d31SJustin Bogner   Ops.push_back(binOpDescriptor(1, Instruction::Shl));
277d449d31SJustin Bogner   Ops.push_back(binOpDescriptor(1, Instruction::LShr));
287d449d31SJustin Bogner   Ops.push_back(binOpDescriptor(1, Instruction::AShr));
297d449d31SJustin Bogner   Ops.push_back(binOpDescriptor(1, Instruction::And));
307d449d31SJustin Bogner   Ops.push_back(binOpDescriptor(1, Instruction::Or));
317d449d31SJustin Bogner   Ops.push_back(binOpDescriptor(1, Instruction::Xor));
327d449d31SJustin Bogner 
337d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_EQ));
347d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_NE));
357d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_UGT));
367d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_UGE));
377d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_ULT));
387d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_ULE));
397d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_SGT));
407d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_SGE));
417d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_SLT));
427d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_SLE));
437d449d31SJustin Bogner }
447d449d31SJustin Bogner 
describeFuzzerFloatOps(std::vector<fuzzerop::OpDescriptor> & Ops)457d449d31SJustin Bogner void llvm::describeFuzzerFloatOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
467d449d31SJustin Bogner   Ops.push_back(binOpDescriptor(1, Instruction::FAdd));
477d449d31SJustin Bogner   Ops.push_back(binOpDescriptor(1, Instruction::FSub));
487d449d31SJustin Bogner   Ops.push_back(binOpDescriptor(1, Instruction::FMul));
497d449d31SJustin Bogner   Ops.push_back(binOpDescriptor(1, Instruction::FDiv));
507d449d31SJustin Bogner   Ops.push_back(binOpDescriptor(1, Instruction::FRem));
517d449d31SJustin Bogner 
527d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_FALSE));
537d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OEQ));
547d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OGT));
557d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OGE));
567d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OLT));
577d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OLE));
587d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_ONE));
597d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_ORD));
607d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UNO));
617d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UEQ));
627d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UGT));
637d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UGE));
647d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_ULT));
657d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_ULE));
667d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UNE));
677d449d31SJustin Bogner   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_TRUE));
687d449d31SJustin Bogner }
697d449d31SJustin Bogner 
describeFuzzerControlFlowOps(std::vector<fuzzerop::OpDescriptor> & Ops)707d449d31SJustin Bogner void llvm::describeFuzzerControlFlowOps(
717d449d31SJustin Bogner     std::vector<fuzzerop::OpDescriptor> &Ops) {
727d449d31SJustin Bogner   Ops.push_back(splitBlockDescriptor(1));
737d449d31SJustin Bogner }
747d449d31SJustin Bogner 
describeFuzzerPointerOps(std::vector<fuzzerop::OpDescriptor> & Ops)757d449d31SJustin Bogner void llvm::describeFuzzerPointerOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
767d449d31SJustin Bogner   Ops.push_back(gepDescriptor(1));
777d449d31SJustin Bogner }
787d449d31SJustin Bogner 
describeFuzzerAggregateOps(std::vector<fuzzerop::OpDescriptor> & Ops)797d449d31SJustin Bogner void llvm::describeFuzzerAggregateOps(
807d449d31SJustin Bogner     std::vector<fuzzerop::OpDescriptor> &Ops) {
817d449d31SJustin Bogner   Ops.push_back(extractValueDescriptor(1));
827d449d31SJustin Bogner   Ops.push_back(insertValueDescriptor(1));
837d449d31SJustin Bogner }
847d449d31SJustin Bogner 
describeFuzzerVectorOps(std::vector<fuzzerop::OpDescriptor> & Ops)857d449d31SJustin Bogner void llvm::describeFuzzerVectorOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
867d449d31SJustin Bogner   Ops.push_back(extractElementDescriptor(1));
877d449d31SJustin Bogner   Ops.push_back(insertElementDescriptor(1));
887d449d31SJustin Bogner   Ops.push_back(shuffleVectorDescriptor(1));
897d449d31SJustin Bogner }
907d449d31SJustin Bogner 
binOpDescriptor(unsigned Weight,Instruction::BinaryOps Op)917d449d31SJustin Bogner OpDescriptor llvm::fuzzerop::binOpDescriptor(unsigned Weight,
927d449d31SJustin Bogner                                              Instruction::BinaryOps Op) {
937d449d31SJustin Bogner   auto buildOp = [Op](ArrayRef<Value *> Srcs, Instruction *Inst) {
947d449d31SJustin Bogner     return BinaryOperator::Create(Op, Srcs[0], Srcs[1], "B", Inst);
957d449d31SJustin Bogner   };
967d449d31SJustin Bogner   switch (Op) {
977d449d31SJustin Bogner   case Instruction::Add:
987d449d31SJustin Bogner   case Instruction::Sub:
997d449d31SJustin Bogner   case Instruction::Mul:
1007d449d31SJustin Bogner   case Instruction::SDiv:
1017d449d31SJustin Bogner   case Instruction::UDiv:
1027d449d31SJustin Bogner   case Instruction::SRem:
1037d449d31SJustin Bogner   case Instruction::URem:
1047d449d31SJustin Bogner   case Instruction::Shl:
1057d449d31SJustin Bogner   case Instruction::LShr:
1067d449d31SJustin Bogner   case Instruction::AShr:
1077d449d31SJustin Bogner   case Instruction::And:
1087d449d31SJustin Bogner   case Instruction::Or:
1097d449d31SJustin Bogner   case Instruction::Xor:
1107d449d31SJustin Bogner     return {Weight, {anyIntType(), matchFirstType()}, buildOp};
1117d449d31SJustin Bogner   case Instruction::FAdd:
1127d449d31SJustin Bogner   case Instruction::FSub:
1137d449d31SJustin Bogner   case Instruction::FMul:
1147d449d31SJustin Bogner   case Instruction::FDiv:
1157d449d31SJustin Bogner   case Instruction::FRem:
1167d449d31SJustin Bogner     return {Weight, {anyFloatType(), matchFirstType()}, buildOp};
1177d449d31SJustin Bogner   case Instruction::BinaryOpsEnd:
1187d449d31SJustin Bogner     llvm_unreachable("Value out of range of enum");
1197d449d31SJustin Bogner   }
1207d449d31SJustin Bogner   llvm_unreachable("Covered switch");
1217d449d31SJustin Bogner }
1227d449d31SJustin Bogner 
cmpOpDescriptor(unsigned Weight,Instruction::OtherOps CmpOp,CmpInst::Predicate Pred)1237d449d31SJustin Bogner OpDescriptor llvm::fuzzerop::cmpOpDescriptor(unsigned Weight,
1247d449d31SJustin Bogner                                              Instruction::OtherOps CmpOp,
1257d449d31SJustin Bogner                                              CmpInst::Predicate Pred) {
1267d449d31SJustin Bogner   auto buildOp = [CmpOp, Pred](ArrayRef<Value *> Srcs, Instruction *Inst) {
1277d449d31SJustin Bogner     return CmpInst::Create(CmpOp, Pred, Srcs[0], Srcs[1], "C", Inst);
1287d449d31SJustin Bogner   };
1297d449d31SJustin Bogner 
1307d449d31SJustin Bogner   switch (CmpOp) {
1317d449d31SJustin Bogner   case Instruction::ICmp:
1327d449d31SJustin Bogner     return {Weight, {anyIntType(), matchFirstType()}, buildOp};
1337d449d31SJustin Bogner   case Instruction::FCmp:
1347d449d31SJustin Bogner     return {Weight, {anyFloatType(), matchFirstType()}, buildOp};
1357d449d31SJustin Bogner   default:
1367d449d31SJustin Bogner     llvm_unreachable("CmpOp must be ICmp or FCmp");
1377d449d31SJustin Bogner   }
1387d449d31SJustin Bogner }
1397d449d31SJustin Bogner 
splitBlockDescriptor(unsigned Weight)1407d449d31SJustin Bogner OpDescriptor llvm::fuzzerop::splitBlockDescriptor(unsigned Weight) {
1417d449d31SJustin Bogner   auto buildSplitBlock = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
1427d449d31SJustin Bogner     BasicBlock *Block = Inst->getParent();
1437d449d31SJustin Bogner     BasicBlock *Next = Block->splitBasicBlock(Inst, "BB");
144541f9707SIgor Laevsky 
145541f9707SIgor Laevsky     // If it was an exception handling block, we are done.
146541f9707SIgor Laevsky     if (Block->isEHPad())
147541f9707SIgor Laevsky       return nullptr;
148541f9707SIgor Laevsky 
1497d449d31SJustin Bogner     // Loop back on this block by replacing the unconditional forward branch
1507d449d31SJustin Bogner     // with a conditional with a backedge.
151541f9707SIgor Laevsky     if (Block != &Block->getParent()->getEntryBlock()) {
1527d449d31SJustin Bogner       BranchInst::Create(Block, Next, Srcs[0], Block->getTerminator());
1537d449d31SJustin Bogner       Block->getTerminator()->eraseFromParent();
1547d449d31SJustin Bogner 
1557d449d31SJustin Bogner       // We need values for each phi in the block. Since there isn't a good way
1567d449d31SJustin Bogner       // to do a variable number of input values currently, we just fill them
1577d449d31SJustin Bogner       // with undef.
1587d449d31SJustin Bogner       for (PHINode &PHI : Block->phis())
1597d449d31SJustin Bogner         PHI.addIncoming(UndefValue::get(PHI.getType()), Block);
1607d449d31SJustin Bogner     }
1617d449d31SJustin Bogner     return nullptr;
1627d449d31SJustin Bogner   };
1637d449d31SJustin Bogner   SourcePred isInt1Ty{[](ArrayRef<Value *>, const Value *V) {
1647d449d31SJustin Bogner                         return V->getType()->isIntegerTy(1);
1657d449d31SJustin Bogner                       },
1667d449d31SJustin Bogner                       None};
1677d449d31SJustin Bogner   return {Weight, {isInt1Ty}, buildSplitBlock};
1687d449d31SJustin Bogner }
1697d449d31SJustin Bogner 
gepDescriptor(unsigned Weight)1707d449d31SJustin Bogner OpDescriptor llvm::fuzzerop::gepDescriptor(unsigned Weight) {
1717d449d31SJustin Bogner   auto buildGEP = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
1723c47dd47SNikita Popov     // TODO: It would be better to generate a random type here, rather than
1733c47dd47SNikita Popov     // generating a random value and picking its type.
1743c47dd47SNikita Popov     Type *Ty = Srcs[0]->getType()->isOpaquePointerTy()
1753c47dd47SNikita Popov                    ? Srcs[1]->getType()
1763c47dd47SNikita Popov                    : Srcs[0]->getType()->getNonOpaquePointerElementType();
1773c47dd47SNikita Popov     auto Indices = makeArrayRef(Srcs).drop_front(2);
1787d449d31SJustin Bogner     return GetElementPtrInst::Create(Ty, Srcs[0], Indices, "G", Inst);
1797d449d31SJustin Bogner   };
1807d449d31SJustin Bogner   // TODO: Handle aggregates and vectors
1817d449d31SJustin Bogner   // TODO: Support multiple indices.
1827d449d31SJustin Bogner   // TODO: Try to avoid meaningless accesses.
1833c47dd47SNikita Popov   SourcePred sizedType(
1843c47dd47SNikita Popov       [](ArrayRef<Value *>, const Value *V) { return V->getType()->isSized(); },
1853c47dd47SNikita Popov       None);
1863c47dd47SNikita Popov   return {Weight, {sizedPtrType(), sizedType, anyIntType()}, buildGEP};
1877d449d31SJustin Bogner }
1887d449d31SJustin Bogner 
getAggregateNumElements(Type * T)1897d449d31SJustin Bogner static uint64_t getAggregateNumElements(Type *T) {
1907d449d31SJustin Bogner   assert(T->isAggregateType() && "Not a struct or array");
1917d449d31SJustin Bogner   if (isa<StructType>(T))
1927d449d31SJustin Bogner     return T->getStructNumElements();
1937d449d31SJustin Bogner   return T->getArrayNumElements();
1947d449d31SJustin Bogner }
1957d449d31SJustin Bogner 
validExtractValueIndex()1967d449d31SJustin Bogner static SourcePred validExtractValueIndex() {
1977d449d31SJustin Bogner   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
1987d449d31SJustin Bogner     if (auto *CI = dyn_cast<ConstantInt>(V))
1997d449d31SJustin Bogner       if (!CI->uge(getAggregateNumElements(Cur[0]->getType())))
2007d449d31SJustin Bogner         return true;
2017d449d31SJustin Bogner     return false;
2027d449d31SJustin Bogner   };
2037d449d31SJustin Bogner   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> Ts) {
2047d449d31SJustin Bogner     std::vector<Constant *> Result;
2057d449d31SJustin Bogner     auto *Int32Ty = Type::getInt32Ty(Cur[0]->getContext());
2067d449d31SJustin Bogner     uint64_t N = getAggregateNumElements(Cur[0]->getType());
2077d449d31SJustin Bogner     // Create indices at the start, end, and middle, but avoid dups.
2087d449d31SJustin Bogner     Result.push_back(ConstantInt::get(Int32Ty, 0));
2097d449d31SJustin Bogner     if (N > 1)
2107d449d31SJustin Bogner       Result.push_back(ConstantInt::get(Int32Ty, N - 1));
2117d449d31SJustin Bogner     if (N > 2)
2127d449d31SJustin Bogner       Result.push_back(ConstantInt::get(Int32Ty, N / 2));
2137d449d31SJustin Bogner     return Result;
2147d449d31SJustin Bogner   };
2157d449d31SJustin Bogner   return {Pred, Make};
2167d449d31SJustin Bogner }
2177d449d31SJustin Bogner 
extractValueDescriptor(unsigned Weight)2187d449d31SJustin Bogner OpDescriptor llvm::fuzzerop::extractValueDescriptor(unsigned Weight) {
2197d449d31SJustin Bogner   auto buildExtract = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
2207d449d31SJustin Bogner     // TODO: It's pretty inefficient to shuffle this all through constants.
2217d449d31SJustin Bogner     unsigned Idx = cast<ConstantInt>(Srcs[1])->getZExtValue();
2227d449d31SJustin Bogner     return ExtractValueInst::Create(Srcs[0], {Idx}, "E", Inst);
2237d449d31SJustin Bogner   };
2247d449d31SJustin Bogner   // TODO: Should we handle multiple indices?
2257d449d31SJustin Bogner   return {Weight, {anyAggregateType(), validExtractValueIndex()}, buildExtract};
2267d449d31SJustin Bogner }
2277d449d31SJustin Bogner 
matchScalarInAggregate()2287d449d31SJustin Bogner static SourcePred matchScalarInAggregate() {
2297d449d31SJustin Bogner   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
23033031926SIgor Laevsky     if (auto *ArrayT = dyn_cast<ArrayType>(Cur[0]->getType()))
23133031926SIgor Laevsky       return V->getType() == ArrayT->getElementType();
23233031926SIgor Laevsky 
2337d449d31SJustin Bogner     auto *STy = cast<StructType>(Cur[0]->getType());
2347d449d31SJustin Bogner     for (int I = 0, E = STy->getNumElements(); I < E; ++I)
2357d449d31SJustin Bogner       if (STy->getTypeAtIndex(I) == V->getType())
2367d449d31SJustin Bogner         return true;
2377d449d31SJustin Bogner     return false;
2387d449d31SJustin Bogner   };
2397d449d31SJustin Bogner   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
24033031926SIgor Laevsky     if (auto *ArrayT = dyn_cast<ArrayType>(Cur[0]->getType()))
24133031926SIgor Laevsky       return makeConstantsWithType(ArrayT->getElementType());
24233031926SIgor Laevsky 
2437d449d31SJustin Bogner     std::vector<Constant *> Result;
2447d449d31SJustin Bogner     auto *STy = cast<StructType>(Cur[0]->getType());
2457d449d31SJustin Bogner     for (int I = 0, E = STy->getNumElements(); I < E; ++I)
2467d449d31SJustin Bogner       makeConstantsWithType(STy->getTypeAtIndex(I), Result);
2477d449d31SJustin Bogner     return Result;
2487d449d31SJustin Bogner   };
2497d449d31SJustin Bogner   return {Pred, Make};
2507d449d31SJustin Bogner }
2517d449d31SJustin Bogner 
validInsertValueIndex()2527d449d31SJustin Bogner static SourcePred validInsertValueIndex() {
2537d449d31SJustin Bogner   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
2547d449d31SJustin Bogner     if (auto *CI = dyn_cast<ConstantInt>(V))
255e24e95feSEli Friedman       if (CI->getBitWidth() == 32) {
256e24e95feSEli Friedman         Type *Indexed = ExtractValueInst::getIndexedType(Cur[0]->getType(),
257e24e95feSEli Friedman                                                          CI->getZExtValue());
258e24e95feSEli Friedman         return Indexed == Cur[1]->getType();
259e24e95feSEli Friedman       }
2607d449d31SJustin Bogner     return false;
2617d449d31SJustin Bogner   };
2627d449d31SJustin Bogner   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> Ts) {
2637d449d31SJustin Bogner     std::vector<Constant *> Result;
2647d449d31SJustin Bogner     auto *Int32Ty = Type::getInt32Ty(Cur[0]->getContext());
265e24e95feSEli Friedman     auto *BaseTy = Cur[0]->getType();
266e24e95feSEli Friedman     int I = 0;
267e24e95feSEli Friedman     while (Type *Indexed = ExtractValueInst::getIndexedType(BaseTy, I)) {
268e24e95feSEli Friedman       if (Indexed == Cur[1]->getType())
2697d449d31SJustin Bogner         Result.push_back(ConstantInt::get(Int32Ty, I));
270e24e95feSEli Friedman       ++I;
271e24e95feSEli Friedman     }
2727d449d31SJustin Bogner     return Result;
2737d449d31SJustin Bogner   };
2747d449d31SJustin Bogner   return {Pred, Make};
2757d449d31SJustin Bogner }
2767d449d31SJustin Bogner 
insertValueDescriptor(unsigned Weight)2777d449d31SJustin Bogner OpDescriptor llvm::fuzzerop::insertValueDescriptor(unsigned Weight) {
2787d449d31SJustin Bogner   auto buildInsert = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
2797d449d31SJustin Bogner     // TODO: It's pretty inefficient to shuffle this all through constants.
2807d449d31SJustin Bogner     unsigned Idx = cast<ConstantInt>(Srcs[2])->getZExtValue();
2817d449d31SJustin Bogner     return InsertValueInst::Create(Srcs[0], Srcs[1], {Idx}, "I", Inst);
2827d449d31SJustin Bogner   };
2837d449d31SJustin Bogner   return {
2847d449d31SJustin Bogner       Weight,
2857d449d31SJustin Bogner       {anyAggregateType(), matchScalarInAggregate(), validInsertValueIndex()},
2867d449d31SJustin Bogner       buildInsert};
2877d449d31SJustin Bogner }
2887d449d31SJustin Bogner 
extractElementDescriptor(unsigned Weight)2897d449d31SJustin Bogner OpDescriptor llvm::fuzzerop::extractElementDescriptor(unsigned Weight) {
2907d449d31SJustin Bogner   auto buildExtract = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
2917d449d31SJustin Bogner     return ExtractElementInst::Create(Srcs[0], Srcs[1], "E", Inst);
2927d449d31SJustin Bogner   };
2937d449d31SJustin Bogner   // TODO: Try to avoid undefined accesses.
2947d449d31SJustin Bogner   return {Weight, {anyVectorType(), anyIntType()}, buildExtract};
2957d449d31SJustin Bogner }
2967d449d31SJustin Bogner 
insertElementDescriptor(unsigned Weight)2977d449d31SJustin Bogner OpDescriptor llvm::fuzzerop::insertElementDescriptor(unsigned Weight) {
2987d449d31SJustin Bogner   auto buildInsert = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
2997d449d31SJustin Bogner     return InsertElementInst::Create(Srcs[0], Srcs[1], Srcs[2], "I", Inst);
3007d449d31SJustin Bogner   };
3017d449d31SJustin Bogner     // TODO: Try to avoid undefined accesses.
3027d449d31SJustin Bogner   return {Weight,
3037d449d31SJustin Bogner           {anyVectorType(), matchScalarOfFirstType(), anyIntType()},
3047d449d31SJustin Bogner           buildInsert};
3057d449d31SJustin Bogner }
3067d449d31SJustin Bogner 
validShuffleVectorIndex()3077d449d31SJustin Bogner static SourcePred validShuffleVectorIndex() {
3087d449d31SJustin Bogner   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
3097d449d31SJustin Bogner     return ShuffleVectorInst::isValidOperands(Cur[0], Cur[1], V);
3107d449d31SJustin Bogner   };
3117d449d31SJustin Bogner   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> Ts) {
312*853beb55SNikita Popov     auto *FirstTy = cast<VectorType>(Cur[0]->getType());
3137d449d31SJustin Bogner     auto *Int32Ty = Type::getInt32Ty(Cur[0]->getContext());
3147d449d31SJustin Bogner     // TODO: It's straighforward to make up reasonable values, but listing them
3157d449d31SJustin Bogner     // exhaustively would be insane. Come up with a couple of sensible ones.
316e8f815a4SChristopher Tetreault     return std::vector<Constant *>{UndefValue::get(
317*853beb55SNikita Popov         VectorType::get(Int32Ty, FirstTy->getElementCount()))};
3187d449d31SJustin Bogner   };
3197d449d31SJustin Bogner   return {Pred, Make};
3207d449d31SJustin Bogner }
3217d449d31SJustin Bogner 
shuffleVectorDescriptor(unsigned Weight)3227d449d31SJustin Bogner OpDescriptor llvm::fuzzerop::shuffleVectorDescriptor(unsigned Weight) {
3237d449d31SJustin Bogner   auto buildShuffle = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
3247d449d31SJustin Bogner     return new ShuffleVectorInst(Srcs[0], Srcs[1], Srcs[2], "S", Inst);
3257d449d31SJustin Bogner   };
3267d449d31SJustin Bogner   return {Weight,
3277d449d31SJustin Bogner           {anyVectorType(), matchFirstType(), validShuffleVectorIndex()},
3287d449d31SJustin Bogner           buildShuffle};
3297d449d31SJustin Bogner }
330