//===-- 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" #include "llvm/IR/Module.h" using namespace llvm; using namespace fuzzerop; Value *RandomIRBuilder::findOrCreateSource(BasicBlock &BB, ArrayRef Insts) { return findOrCreateSource(BB, Insts, {}, anyType()); } Value *RandomIRBuilder::findOrCreateSource(BasicBlock &BB, ArrayRef Insts, ArrayRef 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 Insts, ArrayRef Srcs, SourcePred Pred) { // Generate some constants to choose from. auto RS = makeSampler(Rand); RS.sample(Pred.generate(Srcs, KnownTypes)); assert(!RS.isEmpty() && "Failed to generate sources"); // If we can find a pointer to load from, use it half the time. Value *Ptr = findPointer(BB, Insts, Srcs, Pred); if (Ptr) RS.sample(Ptr, RS.totalWeight()); Value *Result = RS.getSelection(); if (Result != Ptr) return Result; // If we choose the pointer, we need to create a load. auto IP = BB.getFirstInsertionPt(); if (auto *I = dyn_cast(Ptr)) IP = ++I->getIterator(); return new LoadInst(Ptr, "L", &*IP); } 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: if (Operand.getOperandNo() > 2) return false; break; default: break; } return true; } void RandomIRBuilder::connectToSink(BasicBlock &BB, ArrayRef Insts, Value *V) { auto RS = makeSampler(Rand); for (auto &I : Insts) { if (isa(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 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 Insts, ArrayRef Srcs, SourcePred Pred) { auto IsMatchingPtr = [&Srcs, &Pred](Instruction *Inst) { if (auto PtrTy = dyn_cast(Inst->getType())) // 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; }