1*2cab237bSDimitry Andric //===-- Operations.cpp ----------------------------------------------------===//
2*2cab237bSDimitry Andric //
3*2cab237bSDimitry Andric // The LLVM Compiler Infrastructure
4*2cab237bSDimitry Andric //
5*2cab237bSDimitry Andric // This file is distributed under the University of Illinois Open Source
6*2cab237bSDimitry Andric // License. See LICENSE.TXT for details.
7*2cab237bSDimitry Andric //
8*2cab237bSDimitry Andric //===----------------------------------------------------------------------===//
9*2cab237bSDimitry Andric
10*2cab237bSDimitry Andric #include "llvm/FuzzMutate/Operations.h"
11*2cab237bSDimitry Andric #include "llvm/IR/BasicBlock.h"
12*2cab237bSDimitry Andric #include "llvm/IR/Constants.h"
13*2cab237bSDimitry Andric #include "llvm/IR/Function.h"
14*2cab237bSDimitry Andric #include "llvm/IR/Instructions.h"
15*2cab237bSDimitry Andric
16*2cab237bSDimitry Andric using namespace llvm;
17*2cab237bSDimitry Andric using namespace fuzzerop;
18*2cab237bSDimitry Andric
describeFuzzerIntOps(std::vector<fuzzerop::OpDescriptor> & Ops)19*2cab237bSDimitry Andric void llvm::describeFuzzerIntOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
20*2cab237bSDimitry Andric Ops.push_back(binOpDescriptor(1, Instruction::Add));
21*2cab237bSDimitry Andric Ops.push_back(binOpDescriptor(1, Instruction::Sub));
22*2cab237bSDimitry Andric Ops.push_back(binOpDescriptor(1, Instruction::Mul));
23*2cab237bSDimitry Andric Ops.push_back(binOpDescriptor(1, Instruction::SDiv));
24*2cab237bSDimitry Andric Ops.push_back(binOpDescriptor(1, Instruction::UDiv));
25*2cab237bSDimitry Andric Ops.push_back(binOpDescriptor(1, Instruction::SRem));
26*2cab237bSDimitry Andric Ops.push_back(binOpDescriptor(1, Instruction::URem));
27*2cab237bSDimitry Andric Ops.push_back(binOpDescriptor(1, Instruction::Shl));
28*2cab237bSDimitry Andric Ops.push_back(binOpDescriptor(1, Instruction::LShr));
29*2cab237bSDimitry Andric Ops.push_back(binOpDescriptor(1, Instruction::AShr));
30*2cab237bSDimitry Andric Ops.push_back(binOpDescriptor(1, Instruction::And));
31*2cab237bSDimitry Andric Ops.push_back(binOpDescriptor(1, Instruction::Or));
32*2cab237bSDimitry Andric Ops.push_back(binOpDescriptor(1, Instruction::Xor));
33*2cab237bSDimitry Andric
34*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_EQ));
35*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_NE));
36*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_UGT));
37*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_UGE));
38*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_ULT));
39*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_ULE));
40*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_SGT));
41*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_SGE));
42*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_SLT));
43*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_SLE));
44*2cab237bSDimitry Andric }
45*2cab237bSDimitry Andric
describeFuzzerFloatOps(std::vector<fuzzerop::OpDescriptor> & Ops)46*2cab237bSDimitry Andric void llvm::describeFuzzerFloatOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
47*2cab237bSDimitry Andric Ops.push_back(binOpDescriptor(1, Instruction::FAdd));
48*2cab237bSDimitry Andric Ops.push_back(binOpDescriptor(1, Instruction::FSub));
49*2cab237bSDimitry Andric Ops.push_back(binOpDescriptor(1, Instruction::FMul));
50*2cab237bSDimitry Andric Ops.push_back(binOpDescriptor(1, Instruction::FDiv));
51*2cab237bSDimitry Andric Ops.push_back(binOpDescriptor(1, Instruction::FRem));
52*2cab237bSDimitry Andric
53*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_FALSE));
54*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OEQ));
55*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OGT));
56*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OGE));
57*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OLT));
58*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OLE));
59*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_ONE));
60*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_ORD));
61*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UNO));
62*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UEQ));
63*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UGT));
64*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UGE));
65*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_ULT));
66*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_ULE));
67*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UNE));
68*2cab237bSDimitry Andric Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_TRUE));
69*2cab237bSDimitry Andric }
70*2cab237bSDimitry Andric
describeFuzzerControlFlowOps(std::vector<fuzzerop::OpDescriptor> & Ops)71*2cab237bSDimitry Andric void llvm::describeFuzzerControlFlowOps(
72*2cab237bSDimitry Andric std::vector<fuzzerop::OpDescriptor> &Ops) {
73*2cab237bSDimitry Andric Ops.push_back(splitBlockDescriptor(1));
74*2cab237bSDimitry Andric }
75*2cab237bSDimitry Andric
describeFuzzerPointerOps(std::vector<fuzzerop::OpDescriptor> & Ops)76*2cab237bSDimitry Andric void llvm::describeFuzzerPointerOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
77*2cab237bSDimitry Andric Ops.push_back(gepDescriptor(1));
78*2cab237bSDimitry Andric }
79*2cab237bSDimitry Andric
describeFuzzerAggregateOps(std::vector<fuzzerop::OpDescriptor> & Ops)80*2cab237bSDimitry Andric void llvm::describeFuzzerAggregateOps(
81*2cab237bSDimitry Andric std::vector<fuzzerop::OpDescriptor> &Ops) {
82*2cab237bSDimitry Andric Ops.push_back(extractValueDescriptor(1));
83*2cab237bSDimitry Andric Ops.push_back(insertValueDescriptor(1));
84*2cab237bSDimitry Andric }
85*2cab237bSDimitry Andric
describeFuzzerVectorOps(std::vector<fuzzerop::OpDescriptor> & Ops)86*2cab237bSDimitry Andric void llvm::describeFuzzerVectorOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
87*2cab237bSDimitry Andric Ops.push_back(extractElementDescriptor(1));
88*2cab237bSDimitry Andric Ops.push_back(insertElementDescriptor(1));
89*2cab237bSDimitry Andric Ops.push_back(shuffleVectorDescriptor(1));
90*2cab237bSDimitry Andric }
91*2cab237bSDimitry Andric
binOpDescriptor(unsigned Weight,Instruction::BinaryOps Op)92*2cab237bSDimitry Andric OpDescriptor llvm::fuzzerop::binOpDescriptor(unsigned Weight,
93*2cab237bSDimitry Andric Instruction::BinaryOps Op) {
94*2cab237bSDimitry Andric auto buildOp = [Op](ArrayRef<Value *> Srcs, Instruction *Inst) {
95*2cab237bSDimitry Andric return BinaryOperator::Create(Op, Srcs[0], Srcs[1], "B", Inst);
96*2cab237bSDimitry Andric };
97*2cab237bSDimitry Andric switch (Op) {
98*2cab237bSDimitry Andric case Instruction::Add:
99*2cab237bSDimitry Andric case Instruction::Sub:
100*2cab237bSDimitry Andric case Instruction::Mul:
101*2cab237bSDimitry Andric case Instruction::SDiv:
102*2cab237bSDimitry Andric case Instruction::UDiv:
103*2cab237bSDimitry Andric case Instruction::SRem:
104*2cab237bSDimitry Andric case Instruction::URem:
105*2cab237bSDimitry Andric case Instruction::Shl:
106*2cab237bSDimitry Andric case Instruction::LShr:
107*2cab237bSDimitry Andric case Instruction::AShr:
108*2cab237bSDimitry Andric case Instruction::And:
109*2cab237bSDimitry Andric case Instruction::Or:
110*2cab237bSDimitry Andric case Instruction::Xor:
111*2cab237bSDimitry Andric return {Weight, {anyIntType(), matchFirstType()}, buildOp};
112*2cab237bSDimitry Andric case Instruction::FAdd:
113*2cab237bSDimitry Andric case Instruction::FSub:
114*2cab237bSDimitry Andric case Instruction::FMul:
115*2cab237bSDimitry Andric case Instruction::FDiv:
116*2cab237bSDimitry Andric case Instruction::FRem:
117*2cab237bSDimitry Andric return {Weight, {anyFloatType(), matchFirstType()}, buildOp};
118*2cab237bSDimitry Andric case Instruction::BinaryOpsEnd:
119*2cab237bSDimitry Andric llvm_unreachable("Value out of range of enum");
120*2cab237bSDimitry Andric }
121*2cab237bSDimitry Andric llvm_unreachable("Covered switch");
122*2cab237bSDimitry Andric }
123*2cab237bSDimitry Andric
cmpOpDescriptor(unsigned Weight,Instruction::OtherOps CmpOp,CmpInst::Predicate Pred)124*2cab237bSDimitry Andric OpDescriptor llvm::fuzzerop::cmpOpDescriptor(unsigned Weight,
125*2cab237bSDimitry Andric Instruction::OtherOps CmpOp,
126*2cab237bSDimitry Andric CmpInst::Predicate Pred) {
127*2cab237bSDimitry Andric auto buildOp = [CmpOp, Pred](ArrayRef<Value *> Srcs, Instruction *Inst) {
128*2cab237bSDimitry Andric return CmpInst::Create(CmpOp, Pred, Srcs[0], Srcs[1], "C", Inst);
129*2cab237bSDimitry Andric };
130*2cab237bSDimitry Andric
131*2cab237bSDimitry Andric switch (CmpOp) {
132*2cab237bSDimitry Andric case Instruction::ICmp:
133*2cab237bSDimitry Andric return {Weight, {anyIntType(), matchFirstType()}, buildOp};
134*2cab237bSDimitry Andric case Instruction::FCmp:
135*2cab237bSDimitry Andric return {Weight, {anyFloatType(), matchFirstType()}, buildOp};
136*2cab237bSDimitry Andric default:
137*2cab237bSDimitry Andric llvm_unreachable("CmpOp must be ICmp or FCmp");
138*2cab237bSDimitry Andric }
139*2cab237bSDimitry Andric }
140*2cab237bSDimitry Andric
splitBlockDescriptor(unsigned Weight)141*2cab237bSDimitry Andric OpDescriptor llvm::fuzzerop::splitBlockDescriptor(unsigned Weight) {
142*2cab237bSDimitry Andric auto buildSplitBlock = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
143*2cab237bSDimitry Andric BasicBlock *Block = Inst->getParent();
144*2cab237bSDimitry Andric BasicBlock *Next = Block->splitBasicBlock(Inst, "BB");
145*2cab237bSDimitry Andric
146*2cab237bSDimitry Andric // If it was an exception handling block, we are done.
147*2cab237bSDimitry Andric if (Block->isEHPad())
148*2cab237bSDimitry Andric return nullptr;
149*2cab237bSDimitry Andric
150*2cab237bSDimitry Andric // Loop back on this block by replacing the unconditional forward branch
151*2cab237bSDimitry Andric // with a conditional with a backedge.
152*2cab237bSDimitry Andric if (Block != &Block->getParent()->getEntryBlock()) {
153*2cab237bSDimitry Andric BranchInst::Create(Block, Next, Srcs[0], Block->getTerminator());
154*2cab237bSDimitry Andric Block->getTerminator()->eraseFromParent();
155*2cab237bSDimitry Andric
156*2cab237bSDimitry Andric // We need values for each phi in the block. Since there isn't a good way
157*2cab237bSDimitry Andric // to do a variable number of input values currently, we just fill them
158*2cab237bSDimitry Andric // with undef.
159*2cab237bSDimitry Andric for (PHINode &PHI : Block->phis())
160*2cab237bSDimitry Andric PHI.addIncoming(UndefValue::get(PHI.getType()), Block);
161*2cab237bSDimitry Andric }
162*2cab237bSDimitry Andric return nullptr;
163*2cab237bSDimitry Andric };
164*2cab237bSDimitry Andric SourcePred isInt1Ty{[](ArrayRef<Value *>, const Value *V) {
165*2cab237bSDimitry Andric return V->getType()->isIntegerTy(1);
166*2cab237bSDimitry Andric },
167*2cab237bSDimitry Andric None};
168*2cab237bSDimitry Andric return {Weight, {isInt1Ty}, buildSplitBlock};
169*2cab237bSDimitry Andric }
170*2cab237bSDimitry Andric
gepDescriptor(unsigned Weight)171*2cab237bSDimitry Andric OpDescriptor llvm::fuzzerop::gepDescriptor(unsigned Weight) {
172*2cab237bSDimitry Andric auto buildGEP = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
173*2cab237bSDimitry Andric Type *Ty = cast<PointerType>(Srcs[0]->getType())->getElementType();
174*2cab237bSDimitry Andric auto Indices = makeArrayRef(Srcs).drop_front(1);
175*2cab237bSDimitry Andric return GetElementPtrInst::Create(Ty, Srcs[0], Indices, "G", Inst);
176*2cab237bSDimitry Andric };
177*2cab237bSDimitry Andric // TODO: Handle aggregates and vectors
178*2cab237bSDimitry Andric // TODO: Support multiple indices.
179*2cab237bSDimitry Andric // TODO: Try to avoid meaningless accesses.
180*2cab237bSDimitry Andric return {Weight, {sizedPtrType(), anyIntType()}, buildGEP};
181*2cab237bSDimitry Andric }
182*2cab237bSDimitry Andric
getAggregateNumElements(Type * T)183*2cab237bSDimitry Andric static uint64_t getAggregateNumElements(Type *T) {
184*2cab237bSDimitry Andric assert(T->isAggregateType() && "Not a struct or array");
185*2cab237bSDimitry Andric if (isa<StructType>(T))
186*2cab237bSDimitry Andric return T->getStructNumElements();
187*2cab237bSDimitry Andric return T->getArrayNumElements();
188*2cab237bSDimitry Andric }
189*2cab237bSDimitry Andric
validExtractValueIndex()190*2cab237bSDimitry Andric static SourcePred validExtractValueIndex() {
191*2cab237bSDimitry Andric auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
192*2cab237bSDimitry Andric if (auto *CI = dyn_cast<ConstantInt>(V))
193*2cab237bSDimitry Andric if (!CI->uge(getAggregateNumElements(Cur[0]->getType())))
194*2cab237bSDimitry Andric return true;
195*2cab237bSDimitry Andric return false;
196*2cab237bSDimitry Andric };
197*2cab237bSDimitry Andric auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> Ts) {
198*2cab237bSDimitry Andric std::vector<Constant *> Result;
199*2cab237bSDimitry Andric auto *Int32Ty = Type::getInt32Ty(Cur[0]->getContext());
200*2cab237bSDimitry Andric uint64_t N = getAggregateNumElements(Cur[0]->getType());
201*2cab237bSDimitry Andric // Create indices at the start, end, and middle, but avoid dups.
202*2cab237bSDimitry Andric Result.push_back(ConstantInt::get(Int32Ty, 0));
203*2cab237bSDimitry Andric if (N > 1)
204*2cab237bSDimitry Andric Result.push_back(ConstantInt::get(Int32Ty, N - 1));
205*2cab237bSDimitry Andric if (N > 2)
206*2cab237bSDimitry Andric Result.push_back(ConstantInt::get(Int32Ty, N / 2));
207*2cab237bSDimitry Andric return Result;
208*2cab237bSDimitry Andric };
209*2cab237bSDimitry Andric return {Pred, Make};
210*2cab237bSDimitry Andric }
211*2cab237bSDimitry Andric
extractValueDescriptor(unsigned Weight)212*2cab237bSDimitry Andric OpDescriptor llvm::fuzzerop::extractValueDescriptor(unsigned Weight) {
213*2cab237bSDimitry Andric auto buildExtract = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
214*2cab237bSDimitry Andric // TODO: It's pretty inefficient to shuffle this all through constants.
215*2cab237bSDimitry Andric unsigned Idx = cast<ConstantInt>(Srcs[1])->getZExtValue();
216*2cab237bSDimitry Andric return ExtractValueInst::Create(Srcs[0], {Idx}, "E", Inst);
217*2cab237bSDimitry Andric };
218*2cab237bSDimitry Andric // TODO: Should we handle multiple indices?
219*2cab237bSDimitry Andric return {Weight, {anyAggregateType(), validExtractValueIndex()}, buildExtract};
220*2cab237bSDimitry Andric }
221*2cab237bSDimitry Andric
matchScalarInAggregate()222*2cab237bSDimitry Andric static SourcePred matchScalarInAggregate() {
223*2cab237bSDimitry Andric auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
224*2cab237bSDimitry Andric if (auto *ArrayT = dyn_cast<ArrayType>(Cur[0]->getType()))
225*2cab237bSDimitry Andric return V->getType() == ArrayT->getElementType();
226*2cab237bSDimitry Andric
227*2cab237bSDimitry Andric auto *STy = cast<StructType>(Cur[0]->getType());
228*2cab237bSDimitry Andric for (int I = 0, E = STy->getNumElements(); I < E; ++I)
229*2cab237bSDimitry Andric if (STy->getTypeAtIndex(I) == V->getType())
230*2cab237bSDimitry Andric return true;
231*2cab237bSDimitry Andric return false;
232*2cab237bSDimitry Andric };
233*2cab237bSDimitry Andric auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
234*2cab237bSDimitry Andric if (auto *ArrayT = dyn_cast<ArrayType>(Cur[0]->getType()))
235*2cab237bSDimitry Andric return makeConstantsWithType(ArrayT->getElementType());
236*2cab237bSDimitry Andric
237*2cab237bSDimitry Andric std::vector<Constant *> Result;
238*2cab237bSDimitry Andric auto *STy = cast<StructType>(Cur[0]->getType());
239*2cab237bSDimitry Andric for (int I = 0, E = STy->getNumElements(); I < E; ++I)
240*2cab237bSDimitry Andric makeConstantsWithType(STy->getTypeAtIndex(I), Result);
241*2cab237bSDimitry Andric return Result;
242*2cab237bSDimitry Andric };
243*2cab237bSDimitry Andric return {Pred, Make};
244*2cab237bSDimitry Andric }
245*2cab237bSDimitry Andric
validInsertValueIndex()246*2cab237bSDimitry Andric static SourcePred validInsertValueIndex() {
247*2cab237bSDimitry Andric auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
248*2cab237bSDimitry Andric auto *CTy = cast<CompositeType>(Cur[0]->getType());
249*2cab237bSDimitry Andric if (auto *CI = dyn_cast<ConstantInt>(V))
250*2cab237bSDimitry Andric if (CI->getBitWidth() == 32 &&
251*2cab237bSDimitry Andric CTy->getTypeAtIndex(CI->getZExtValue()) == Cur[1]->getType())
252*2cab237bSDimitry Andric return true;
253*2cab237bSDimitry Andric return false;
254*2cab237bSDimitry Andric };
255*2cab237bSDimitry Andric auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> Ts) {
256*2cab237bSDimitry Andric std::vector<Constant *> Result;
257*2cab237bSDimitry Andric auto *Int32Ty = Type::getInt32Ty(Cur[0]->getContext());
258*2cab237bSDimitry Andric auto *CTy = cast<CompositeType>(Cur[0]->getType());
259*2cab237bSDimitry Andric for (int I = 0, E = getAggregateNumElements(CTy); I < E; ++I)
260*2cab237bSDimitry Andric if (CTy->getTypeAtIndex(I) == Cur[1]->getType())
261*2cab237bSDimitry Andric Result.push_back(ConstantInt::get(Int32Ty, I));
262*2cab237bSDimitry Andric return Result;
263*2cab237bSDimitry Andric };
264*2cab237bSDimitry Andric return {Pred, Make};
265*2cab237bSDimitry Andric }
266*2cab237bSDimitry Andric
insertValueDescriptor(unsigned Weight)267*2cab237bSDimitry Andric OpDescriptor llvm::fuzzerop::insertValueDescriptor(unsigned Weight) {
268*2cab237bSDimitry Andric auto buildInsert = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
269*2cab237bSDimitry Andric // TODO: It's pretty inefficient to shuffle this all through constants.
270*2cab237bSDimitry Andric unsigned Idx = cast<ConstantInt>(Srcs[2])->getZExtValue();
271*2cab237bSDimitry Andric return InsertValueInst::Create(Srcs[0], Srcs[1], {Idx}, "I", Inst);
272*2cab237bSDimitry Andric };
273*2cab237bSDimitry Andric return {
274*2cab237bSDimitry Andric Weight,
275*2cab237bSDimitry Andric {anyAggregateType(), matchScalarInAggregate(), validInsertValueIndex()},
276*2cab237bSDimitry Andric buildInsert};
277*2cab237bSDimitry Andric }
278*2cab237bSDimitry Andric
extractElementDescriptor(unsigned Weight)279*2cab237bSDimitry Andric OpDescriptor llvm::fuzzerop::extractElementDescriptor(unsigned Weight) {
280*2cab237bSDimitry Andric auto buildExtract = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
281*2cab237bSDimitry Andric return ExtractElementInst::Create(Srcs[0], Srcs[1], "E", Inst);
282*2cab237bSDimitry Andric };
283*2cab237bSDimitry Andric // TODO: Try to avoid undefined accesses.
284*2cab237bSDimitry Andric return {Weight, {anyVectorType(), anyIntType()}, buildExtract};
285*2cab237bSDimitry Andric }
286*2cab237bSDimitry Andric
insertElementDescriptor(unsigned Weight)287*2cab237bSDimitry Andric OpDescriptor llvm::fuzzerop::insertElementDescriptor(unsigned Weight) {
288*2cab237bSDimitry Andric auto buildInsert = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
289*2cab237bSDimitry Andric return InsertElementInst::Create(Srcs[0], Srcs[1], Srcs[2], "I", Inst);
290*2cab237bSDimitry Andric };
291*2cab237bSDimitry Andric // TODO: Try to avoid undefined accesses.
292*2cab237bSDimitry Andric return {Weight,
293*2cab237bSDimitry Andric {anyVectorType(), matchScalarOfFirstType(), anyIntType()},
294*2cab237bSDimitry Andric buildInsert};
295*2cab237bSDimitry Andric }
296*2cab237bSDimitry Andric
validShuffleVectorIndex()297*2cab237bSDimitry Andric static SourcePred validShuffleVectorIndex() {
298*2cab237bSDimitry Andric auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
299*2cab237bSDimitry Andric return ShuffleVectorInst::isValidOperands(Cur[0], Cur[1], V);
300*2cab237bSDimitry Andric };
301*2cab237bSDimitry Andric auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> Ts) {
302*2cab237bSDimitry Andric auto *FirstTy = cast<VectorType>(Cur[0]->getType());
303*2cab237bSDimitry Andric auto *Int32Ty = Type::getInt32Ty(Cur[0]->getContext());
304*2cab237bSDimitry Andric // TODO: It's straighforward to make up reasonable values, but listing them
305*2cab237bSDimitry Andric // exhaustively would be insane. Come up with a couple of sensible ones.
306*2cab237bSDimitry Andric return std::vector<Constant *>{
307*2cab237bSDimitry Andric UndefValue::get(VectorType::get(Int32Ty, FirstTy->getNumElements()))};
308*2cab237bSDimitry Andric };
309*2cab237bSDimitry Andric return {Pred, Make};
310*2cab237bSDimitry Andric }
311*2cab237bSDimitry Andric
shuffleVectorDescriptor(unsigned Weight)312*2cab237bSDimitry Andric OpDescriptor llvm::fuzzerop::shuffleVectorDescriptor(unsigned Weight) {
313*2cab237bSDimitry Andric auto buildShuffle = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
314*2cab237bSDimitry Andric return new ShuffleVectorInst(Srcs[0], Srcs[1], Srcs[2], "S", Inst);
315*2cab237bSDimitry Andric };
316*2cab237bSDimitry Andric return {Weight,
317*2cab237bSDimitry Andric {anyVectorType(), matchFirstType(), validShuffleVectorIndex()},
318*2cab237bSDimitry Andric buildShuffle};
319*2cab237bSDimitry Andric }
320