17d449d31SJustin Bogner //===-- RandomIRBuilder.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/RandomIRBuilder.h"
107d449d31SJustin Bogner #include "llvm/ADT/STLExtras.h"
11*ed98c1b3Sserge-sans-paille #include "llvm/FuzzMutate/OpDescriptor.h"
127d449d31SJustin Bogner #include "llvm/FuzzMutate/Random.h"
137d449d31SJustin Bogner #include "llvm/IR/BasicBlock.h"
147d449d31SJustin Bogner #include "llvm/IR/Constants.h"
157d449d31SJustin Bogner #include "llvm/IR/Instructions.h"
167d449d31SJustin Bogner #include "llvm/IR/IntrinsicInst.h"
177d449d31SJustin Bogner 
187d449d31SJustin Bogner using namespace llvm;
197d449d31SJustin Bogner using namespace fuzzerop;
207d449d31SJustin Bogner 
findOrCreateSource(BasicBlock & BB,ArrayRef<Instruction * > Insts)217d449d31SJustin Bogner Value *RandomIRBuilder::findOrCreateSource(BasicBlock &BB,
227d449d31SJustin Bogner                                            ArrayRef<Instruction *> Insts) {
237d449d31SJustin Bogner   return findOrCreateSource(BB, Insts, {}, anyType());
247d449d31SJustin Bogner }
257d449d31SJustin Bogner 
findOrCreateSource(BasicBlock & BB,ArrayRef<Instruction * > Insts,ArrayRef<Value * > Srcs,SourcePred Pred)267d449d31SJustin Bogner Value *RandomIRBuilder::findOrCreateSource(BasicBlock &BB,
277d449d31SJustin Bogner                                            ArrayRef<Instruction *> Insts,
287d449d31SJustin Bogner                                            ArrayRef<Value *> Srcs,
297d449d31SJustin Bogner                                            SourcePred Pred) {
307d449d31SJustin Bogner   auto MatchesPred = [&Srcs, &Pred](Instruction *Inst) {
317d449d31SJustin Bogner     return Pred.matches(Srcs, Inst);
327d449d31SJustin Bogner   };
337d449d31SJustin Bogner   auto RS = makeSampler(Rand, make_filter_range(Insts, MatchesPred));
347d449d31SJustin Bogner   // Also consider choosing no source, meaning we want a new one.
357d449d31SJustin Bogner   RS.sample(nullptr, /*Weight=*/1);
367d449d31SJustin Bogner   if (Instruction *Src = RS.getSelection())
377d449d31SJustin Bogner     return Src;
387d449d31SJustin Bogner   return newSource(BB, Insts, Srcs, Pred);
397d449d31SJustin Bogner }
407d449d31SJustin Bogner 
newSource(BasicBlock & BB,ArrayRef<Instruction * > Insts,ArrayRef<Value * > Srcs,SourcePred Pred)417d449d31SJustin Bogner Value *RandomIRBuilder::newSource(BasicBlock &BB, ArrayRef<Instruction *> Insts,
427d449d31SJustin Bogner                                   ArrayRef<Value *> Srcs, SourcePred Pred) {
437d449d31SJustin Bogner   // Generate some constants to choose from.
447d449d31SJustin Bogner   auto RS = makeSampler<Value *>(Rand);
457d449d31SJustin Bogner   RS.sample(Pred.generate(Srcs, KnownTypes));
467d449d31SJustin Bogner 
477d449d31SJustin Bogner   // If we can find a pointer to load from, use it half the time.
487d449d31SJustin Bogner   Value *Ptr = findPointer(BB, Insts, Srcs, Pred);
49faacdf8dSIgor Laevsky   if (Ptr) {
50faacdf8dSIgor Laevsky     // Create load from the chosen pointer
517d449d31SJustin Bogner     auto IP = BB.getFirstInsertionPt();
5276b36d3aSIgor Laevsky     if (auto *I = dyn_cast<Instruction>(Ptr)) {
537d449d31SJustin Bogner       IP = ++I->getIterator();
5476b36d3aSIgor Laevsky       assert(IP != BB.end() && "guaranteed by the findPointer");
5576b36d3aSIgor Laevsky     }
563c47dd47SNikita Popov     // For opaque pointers, pick the type independently.
573c47dd47SNikita Popov     Type *AccessTy = Ptr->getType()->isOpaquePointerTy()
583c47dd47SNikita Popov                          ? RS.getSelection()->getType()
593c47dd47SNikita Popov                          : Ptr->getType()->getNonOpaquePointerElementType();
603c47dd47SNikita Popov     auto *NewLoad = new LoadInst(AccessTy, Ptr, "L", &*IP);
61faacdf8dSIgor Laevsky 
62faacdf8dSIgor Laevsky     // Only sample this load if it really matches the descriptor
63faacdf8dSIgor Laevsky     if (Pred.matches(Srcs, NewLoad))
64faacdf8dSIgor Laevsky       RS.sample(NewLoad, RS.totalWeight());
65faacdf8dSIgor Laevsky     else
66faacdf8dSIgor Laevsky       NewLoad->eraseFromParent();
67faacdf8dSIgor Laevsky   }
68faacdf8dSIgor Laevsky 
69faacdf8dSIgor Laevsky   assert(!RS.isEmpty() && "Failed to generate sources");
70faacdf8dSIgor Laevsky   return RS.getSelection();
717d449d31SJustin Bogner }
727d449d31SJustin Bogner 
isCompatibleReplacement(const Instruction * I,const Use & Operand,const Value * Replacement)737d449d31SJustin Bogner static bool isCompatibleReplacement(const Instruction *I, const Use &Operand,
747d449d31SJustin Bogner                                     const Value *Replacement) {
757d449d31SJustin Bogner   if (Operand->getType() != Replacement->getType())
767d449d31SJustin Bogner     return false;
777d449d31SJustin Bogner   switch (I->getOpcode()) {
787d449d31SJustin Bogner   case Instruction::GetElementPtr:
797d449d31SJustin Bogner   case Instruction::ExtractElement:
807d449d31SJustin Bogner   case Instruction::ExtractValue:
817d449d31SJustin Bogner     // TODO: We could potentially validate these, but for now just leave indices
827d449d31SJustin Bogner     // alone.
8365902db2SIgor Laevsky     if (Operand.getOperandNo() >= 1)
847d449d31SJustin Bogner       return false;
857d449d31SJustin Bogner     break;
867d449d31SJustin Bogner   case Instruction::InsertValue:
877d449d31SJustin Bogner   case Instruction::InsertElement:
8865902db2SIgor Laevsky   case Instruction::ShuffleVector:
8965902db2SIgor Laevsky     if (Operand.getOperandNo() >= 2)
907d449d31SJustin Bogner       return false;
917d449d31SJustin Bogner     break;
927d449d31SJustin Bogner   default:
937d449d31SJustin Bogner     break;
947d449d31SJustin Bogner   }
957d449d31SJustin Bogner   return true;
967d449d31SJustin Bogner }
977d449d31SJustin Bogner 
connectToSink(BasicBlock & BB,ArrayRef<Instruction * > Insts,Value * V)987d449d31SJustin Bogner void RandomIRBuilder::connectToSink(BasicBlock &BB,
997d449d31SJustin Bogner                                     ArrayRef<Instruction *> Insts, Value *V) {
1007d449d31SJustin Bogner   auto RS = makeSampler<Use *>(Rand);
1017d449d31SJustin Bogner   for (auto &I : Insts) {
1027d449d31SJustin Bogner     if (isa<IntrinsicInst>(I))
1037d449d31SJustin Bogner       // TODO: Replacing operands of intrinsics would be interesting, but
1047d449d31SJustin Bogner       // there's no easy way to verify that a given replacement is valid given
1057d449d31SJustin Bogner       // that intrinsics can impose arbitrary constraints.
1067d449d31SJustin Bogner       continue;
1077d449d31SJustin Bogner     for (Use &U : I->operands())
1087d449d31SJustin Bogner       if (isCompatibleReplacement(I, U, V))
1097d449d31SJustin Bogner         RS.sample(&U, 1);
1107d449d31SJustin Bogner   }
1117d449d31SJustin Bogner   // Also consider choosing no sink, meaning we want a new one.
1127d449d31SJustin Bogner   RS.sample(nullptr, /*Weight=*/1);
1137d449d31SJustin Bogner 
1147d449d31SJustin Bogner   if (Use *Sink = RS.getSelection()) {
1157d449d31SJustin Bogner     User *U = Sink->getUser();
1167d449d31SJustin Bogner     unsigned OpNo = Sink->getOperandNo();
1177d449d31SJustin Bogner     U->setOperand(OpNo, V);
1187d449d31SJustin Bogner     return;
1197d449d31SJustin Bogner   }
1207d449d31SJustin Bogner   newSink(BB, Insts, V);
1217d449d31SJustin Bogner }
1227d449d31SJustin Bogner 
newSink(BasicBlock & BB,ArrayRef<Instruction * > Insts,Value * V)1237d449d31SJustin Bogner void RandomIRBuilder::newSink(BasicBlock &BB, ArrayRef<Instruction *> Insts,
1247d449d31SJustin Bogner                               Value *V) {
1257d449d31SJustin Bogner   Value *Ptr = findPointer(BB, Insts, {V}, matchFirstType());
1267d449d31SJustin Bogner   if (!Ptr) {
1277d449d31SJustin Bogner     if (uniform(Rand, 0, 1))
1287d449d31SJustin Bogner       Ptr = new AllocaInst(V->getType(), 0, "A", &*BB.getFirstInsertionPt());
1297d449d31SJustin Bogner     else
1307d449d31SJustin Bogner       Ptr = UndefValue::get(PointerType::get(V->getType(), 0));
1317d449d31SJustin Bogner   }
1327d449d31SJustin Bogner 
1337d449d31SJustin Bogner   new StoreInst(V, Ptr, Insts.back());
1347d449d31SJustin Bogner }
1357d449d31SJustin Bogner 
findPointer(BasicBlock & BB,ArrayRef<Instruction * > Insts,ArrayRef<Value * > Srcs,SourcePred Pred)1367d449d31SJustin Bogner Value *RandomIRBuilder::findPointer(BasicBlock &BB,
1377d449d31SJustin Bogner                                     ArrayRef<Instruction *> Insts,
1387d449d31SJustin Bogner                                     ArrayRef<Value *> Srcs, SourcePred Pred) {
1397d449d31SJustin Bogner   auto IsMatchingPtr = [&Srcs, &Pred](Instruction *Inst) {
14076b36d3aSIgor Laevsky     // Invoke instructions sometimes produce valid pointers but currently
14176b36d3aSIgor Laevsky     // we can't insert loads or stores from them
1429ae926b9SChandler Carruth     if (Inst->isTerminator())
14376b36d3aSIgor Laevsky       return false;
14476b36d3aSIgor Laevsky 
1453c47dd47SNikita Popov     if (auto *PtrTy = dyn_cast<PointerType>(Inst->getType())) {
1463c47dd47SNikita Popov       if (PtrTy->isOpaque())
1473c47dd47SNikita Popov         return true;
1483c47dd47SNikita Popov 
149d209ff98SIgor Laevsky       // We can never generate loads from non first class or non sized types
1503c47dd47SNikita Popov       Type *ElemTy = PtrTy->getNonOpaquePointerElementType();
151aa97bc11SNikita Popov       if (!ElemTy->isSized() || !ElemTy->isFirstClassType())
152d209ff98SIgor Laevsky         return false;
153d209ff98SIgor Laevsky 
1547d449d31SJustin Bogner       // TODO: Check if this is horribly expensive.
155aa97bc11SNikita Popov       return Pred.matches(Srcs, UndefValue::get(ElemTy));
156d209ff98SIgor Laevsky     }
1577d449d31SJustin Bogner     return false;
1587d449d31SJustin Bogner   };
1597d449d31SJustin Bogner   if (auto RS = makeSampler(Rand, make_filter_range(Insts, IsMatchingPtr)))
1607d449d31SJustin Bogner     return RS.getSelection();
1617d449d31SJustin Bogner   return nullptr;
1627d449d31SJustin Bogner }
163