157 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- 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/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(
 | |
|         cast<PointerType>(Ptr->getType())->getElementType(), 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 (Inst->isTerminator())
 | |
|       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;
 | |
| }
 |