| //===-- RandomIRBuilder.cpp -----------------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/FuzzMutate/RandomIRBuilder.h" | |
| #include "llvm/ADT/STLExtras.h" | |
| #include "llvm/FuzzMutate/OpDescriptor.h" | |
| #include "llvm/FuzzMutate/Random.h" | |
| #include "llvm/IR/BasicBlock.h" | |
| #include "llvm/IR/Constants.h" | |
| #include "llvm/IR/DataLayout.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, | |
| bool allowConstant) { | |
| 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, allowConstant); | |
| } | |
| Value *RandomIRBuilder::newSource(BasicBlock &BB, ArrayRef<Instruction *> Insts, | |
| ArrayRef<Value *> Srcs, SourcePred Pred, | |
| bool allowConstant) { | |
| // 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"); | |
| } | |
| // For opaque pointers, pick the type independently. | |
| Type *AccessTy = Ptr->getType()->isOpaquePointerTy() | |
| ? RS.getSelection()->getType() | |
| : Ptr->getType()->getNonOpaquePointerElementType(); | |
| auto *NewLoad = new LoadInst(AccessTy, 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(); | |
| } | |
| Value *newSrc = RS.getSelection(); | |
| // Generate a stack alloca and store the constant to it if constant is not | |
| // allowed, our hope is that later mutations can generate some values and | |
| // store to this placeholder. | |
| if (!allowConstant && isa<Constant>(newSrc)) { | |
| Type *Ty = newSrc->getType(); | |
| Function *F = BB.getParent(); | |
| BasicBlock *EntryBB = &F->getEntryBlock(); | |
| /// TODO: For all Allocas, maybe allocate an array. | |
| DataLayout DL(BB.getParent()->getParent()); | |
| AllocaInst *Alloca = new AllocaInst(Ty, DL.getProgramAddressSpace(), "A", | |
| EntryBB->getTerminator()); | |
| new StoreInst(newSrc, Alloca, EntryBB->getTerminator()); | |
| if (BB.getTerminator()) { | |
| newSrc = new LoadInst(Ty, Alloca, /*ArrLen,*/ "L", BB.getTerminator()); | |
| } else { | |
| newSrc = new LoadInst(Ty, Alloca, /*ArrLen,*/ "L", &BB); | |
| } | |
| } | |
| return newSrc; | |
| } | |
| static bool isCompatibleReplacement(const Instruction *I, const Use &Operand, | |
| const Value *Replacement) { | |
| unsigned int OperandNo = Operand.getOperandNo(); | |
| 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 (OperandNo >= 1) | |
| return false; | |
| break; | |
| case Instruction::InsertValue: | |
| case Instruction::InsertElement: | |
| case Instruction::ShuffleVector: | |
| if (OperandNo >= 2) | |
| return false; | |
| break; | |
| // For Br/Switch, we only try to modify the 1st Operand (condition). | |
| // Modify other operands, like switch case may accidently change case from | |
| // ConstantInt to a register, which is illegal. | |
| case Instruction::Switch: | |
| case Instruction::Br: | |
| if (OperandNo >= 1) | |
| 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 (Inst->isTerminator()) | |
| return false; | |
| if (auto *PtrTy = dyn_cast<PointerType>(Inst->getType())) { | |
| if (PtrTy->isOpaque()) | |
| return true; | |
| // We can never generate loads from non first class or non sized types | |
| Type *ElemTy = PtrTy->getNonOpaquePointerElementType(); | |
| if (!ElemTy->isSized() || !ElemTy->isFirstClassType()) | |
| return false; | |
| // TODO: Check if this is horribly expensive. | |
| return Pred.matches(Srcs, UndefValue::get(ElemTy)); | |
| } | |
| return false; | |
| }; | |
| if (auto RS = makeSampler(Rand, make_filter_range(Insts, IsMatchingPtr))) | |
| return RS.getSelection(); | |
| return nullptr; | |
| } | |
| Type *RandomIRBuilder::randomType() { | |
| uint64_t TyIdx = uniform<uint64_t>(Rand, 0, KnownTypes.size() - 1); | |
| return KnownTypes[TyIdx]; | |
| } |