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