| //===-- RandomIRBuilder.cpp -----------------------------------------------===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/FuzzMutate/RandomIRBuilder.h" | |
| #include "llvm/ADT/STLExtras.h" | |
| #include "llvm/FuzzMutate/Random.h" | |
| #include "llvm/IR/BasicBlock.h" | |
| #include "llvm/IR/Constants.h" | |
| #include "llvm/IR/Function.h" | |
| #include "llvm/IR/Instructions.h" | |
| #include "llvm/IR/IntrinsicInst.h" | |
| using namespace llvm; | |
| using namespace fuzzerop; | |
| Value *RandomIRBuilder::findOrCreateSource(BasicBlock &BB, | |
| ArrayRef<Instruction *> Insts) { | |
| return findOrCreateSource(BB, Insts, {}, anyType()); | |
| } | |
| Value *RandomIRBuilder::findOrCreateSource(BasicBlock &BB, | |
| ArrayRef<Instruction *> Insts, | |
| ArrayRef<Value *> Srcs, | |
| SourcePred Pred) { | |
| auto MatchesPred = [&Srcs, &Pred](Instruction *Inst) { | |
| return Pred.matches(Srcs, Inst); | |
| }; | |
| auto RS = makeSampler(Rand, make_filter_range(Insts, MatchesPred)); | |
| // Also consider choosing no source, meaning we want a new one. | |
| RS.sample(nullptr, /*Weight=*/1); | |
| if (Instruction *Src = RS.getSelection()) | |
| return Src; | |
| return newSource(BB, Insts, Srcs, Pred); | |
| } | |
| Value *RandomIRBuilder::newSource(BasicBlock &BB, ArrayRef<Instruction *> Insts, | |
| ArrayRef<Value *> Srcs, SourcePred Pred) { | |
| // Generate some constants to choose from. | |
| auto RS = makeSampler<Value *>(Rand); | |
| RS.sample(Pred.generate(Srcs, KnownTypes)); | |
| // If we can find a pointer to load from, use it half the time. | |
| Value *Ptr = findPointer(BB, Insts, Srcs, Pred); | |
| if (Ptr) { | |
| // Create load from the chosen pointer | |
| auto IP = BB.getFirstInsertionPt(); | |
| if (auto *I = dyn_cast<Instruction>(Ptr)) { | |
| IP = ++I->getIterator(); | |
| assert(IP != BB.end() && "guaranteed by the findPointer"); | |
| } | |
| auto *NewLoad = new LoadInst(Ptr, "L", &*IP); | |
| // Only sample this load if it really matches the descriptor | |
| if (Pred.matches(Srcs, NewLoad)) | |
| RS.sample(NewLoad, RS.totalWeight()); | |
| else | |
| NewLoad->eraseFromParent(); | |
| } | |
| assert(!RS.isEmpty() && "Failed to generate sources"); | |
| return RS.getSelection(); | |
| } | |
| static bool isCompatibleReplacement(const Instruction *I, const Use &Operand, | |
| const Value *Replacement) { | |
| if (Operand->getType() != Replacement->getType()) | |
| return false; | |
| switch (I->getOpcode()) { | |
| case Instruction::GetElementPtr: | |
| case Instruction::ExtractElement: | |
| case Instruction::ExtractValue: | |
| // TODO: We could potentially validate these, but for now just leave indices | |
| // alone. | |
| if (Operand.getOperandNo() >= 1) | |
| return false; | |
| break; | |
| case Instruction::InsertValue: | |
| case Instruction::InsertElement: | |
| case Instruction::ShuffleVector: | |
| if (Operand.getOperandNo() >= 2) | |
| return false; | |
| break; | |
| default: | |
| break; | |
| } | |
| return true; | |
| } | |
| void RandomIRBuilder::connectToSink(BasicBlock &BB, | |
| ArrayRef<Instruction *> Insts, Value *V) { | |
| auto RS = makeSampler<Use *>(Rand); | |
| for (auto &I : Insts) { | |
| if (isa<IntrinsicInst>(I)) | |
| // TODO: Replacing operands of intrinsics would be interesting, but | |
| // there's no easy way to verify that a given replacement is valid given | |
| // that intrinsics can impose arbitrary constraints. | |
| continue; | |
| for (Use &U : I->operands()) | |
| if (isCompatibleReplacement(I, U, V)) | |
| RS.sample(&U, 1); | |
| } | |
| // Also consider choosing no sink, meaning we want a new one. | |
| RS.sample(nullptr, /*Weight=*/1); | |
| if (Use *Sink = RS.getSelection()) { | |
| User *U = Sink->getUser(); | |
| unsigned OpNo = Sink->getOperandNo(); | |
| U->setOperand(OpNo, V); | |
| return; | |
| } | |
| newSink(BB, Insts, V); | |
| } | |
| void RandomIRBuilder::newSink(BasicBlock &BB, ArrayRef<Instruction *> Insts, | |
| Value *V) { | |
| Value *Ptr = findPointer(BB, Insts, {V}, matchFirstType()); | |
| if (!Ptr) { | |
| if (uniform(Rand, 0, 1)) | |
| Ptr = new AllocaInst(V->getType(), 0, "A", &*BB.getFirstInsertionPt()); | |
| else | |
| Ptr = UndefValue::get(PointerType::get(V->getType(), 0)); | |
| } | |
| new StoreInst(V, Ptr, Insts.back()); | |
| } | |
| Value *RandomIRBuilder::findPointer(BasicBlock &BB, | |
| ArrayRef<Instruction *> Insts, | |
| ArrayRef<Value *> Srcs, SourcePred Pred) { | |
| auto IsMatchingPtr = [&Srcs, &Pred](Instruction *Inst) { | |
| // Invoke instructions sometimes produce valid pointers but currently | |
| // we can't insert loads or stores from them | |
| if (isa<TerminatorInst>(Inst)) | |
| return false; | |
| if (auto PtrTy = dyn_cast<PointerType>(Inst->getType())) { | |
| // We can never generate loads from non first class or non sized types | |
| if (!PtrTy->getElementType()->isSized() || | |
| !PtrTy->getElementType()->isFirstClassType()) | |
| return false; | |
| // TODO: Check if this is horribly expensive. | |
| return Pred.matches(Srcs, UndefValue::get(PtrTy->getElementType())); | |
| } | |
| return false; | |
| }; | |
| if (auto RS = makeSampler(Rand, make_filter_range(Insts, IsMatchingPtr))) | |
| return RS.getSelection(); | |
| return nullptr; | |
| } |