LCOV - code coverage report
Current view: top level - lib/FuzzMutate - Operations.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 152 187 81.3 %
Date: 2017-09-14 15:23:50 Functions: 27 34 79.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===-- Operations.cpp ----------------------------------------------------===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : 
      10             : #include "llvm/FuzzMutate/Operations.h"
      11             : #include "llvm/IR/BasicBlock.h"
      12             : #include "llvm/IR/Constants.h"
      13             : #include "llvm/IR/Function.h"
      14             : #include "llvm/IR/Instructions.h"
      15             : 
      16             : using namespace llvm;
      17             : using namespace fuzzerop;
      18             : 
      19           4 : void llvm::describeFuzzerIntOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
      20           8 :   Ops.push_back(binOpDescriptor(1, Instruction::Add));
      21           8 :   Ops.push_back(binOpDescriptor(1, Instruction::Sub));
      22           8 :   Ops.push_back(binOpDescriptor(1, Instruction::Mul));
      23           8 :   Ops.push_back(binOpDescriptor(1, Instruction::SDiv));
      24           8 :   Ops.push_back(binOpDescriptor(1, Instruction::UDiv));
      25           8 :   Ops.push_back(binOpDescriptor(1, Instruction::SRem));
      26           8 :   Ops.push_back(binOpDescriptor(1, Instruction::URem));
      27           8 :   Ops.push_back(binOpDescriptor(1, Instruction::Shl));
      28           8 :   Ops.push_back(binOpDescriptor(1, Instruction::LShr));
      29           8 :   Ops.push_back(binOpDescriptor(1, Instruction::AShr));
      30           8 :   Ops.push_back(binOpDescriptor(1, Instruction::And));
      31           8 :   Ops.push_back(binOpDescriptor(1, Instruction::Or));
      32           8 :   Ops.push_back(binOpDescriptor(1, Instruction::Xor));
      33             : 
      34           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_EQ));
      35           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_NE));
      36           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_UGT));
      37           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_UGE));
      38           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_ULT));
      39           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_ULE));
      40           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_SGT));
      41           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_SGE));
      42           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_SLT));
      43           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::ICmp, CmpInst::ICMP_SLE));
      44           4 : }
      45             : 
      46           4 : void llvm::describeFuzzerFloatOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
      47           8 :   Ops.push_back(binOpDescriptor(1, Instruction::FAdd));
      48           8 :   Ops.push_back(binOpDescriptor(1, Instruction::FSub));
      49           8 :   Ops.push_back(binOpDescriptor(1, Instruction::FMul));
      50           8 :   Ops.push_back(binOpDescriptor(1, Instruction::FDiv));
      51           8 :   Ops.push_back(binOpDescriptor(1, Instruction::FRem));
      52             : 
      53           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_FALSE));
      54           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OEQ));
      55           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OGT));
      56           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OGE));
      57           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OLT));
      58           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_OLE));
      59           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_ONE));
      60           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_ORD));
      61           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UNO));
      62           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UEQ));
      63           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UGT));
      64           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UGE));
      65           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_ULT));
      66           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_ULE));
      67           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_UNE));
      68           8 :   Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_TRUE));
      69           4 : }
      70             : 
      71           4 : void llvm::describeFuzzerControlFlowOps(
      72             :     std::vector<fuzzerop::OpDescriptor> &Ops) {
      73           8 :   Ops.push_back(splitBlockDescriptor(1));
      74           4 : }
      75             : 
      76           4 : void llvm::describeFuzzerPointerOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
      77           8 :   Ops.push_back(gepDescriptor(1));
      78           4 : }
      79             : 
      80           4 : void llvm::describeFuzzerAggregateOps(
      81             :     std::vector<fuzzerop::OpDescriptor> &Ops) {
      82           8 :   Ops.push_back(extractValueDescriptor(1));
      83           8 :   Ops.push_back(insertValueDescriptor(1));
      84           4 : }
      85             : 
      86           4 : void llvm::describeFuzzerVectorOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
      87           8 :   Ops.push_back(extractElementDescriptor(1));
      88           8 :   Ops.push_back(insertElementDescriptor(1));
      89           8 :   Ops.push_back(shuffleVectorDescriptor(1));
      90           4 : }
      91             : 
      92          72 : OpDescriptor llvm::fuzzerop::binOpDescriptor(unsigned Weight,
      93             :                                              Instruction::BinaryOps Op) {
      94           0 :   auto buildOp = [Op](ArrayRef<Value *> Srcs, Instruction *Inst) {
      95           0 :     return BinaryOperator::Create(Op, Srcs[0], Srcs[1], "B", Inst);
      96          72 :   };
      97             :   switch (Op) {
      98          52 :   case Instruction::Add:
      99             :   case Instruction::Sub:
     100             :   case Instruction::Mul:
     101             :   case Instruction::SDiv:
     102             :   case Instruction::UDiv:
     103             :   case Instruction::SRem:
     104             :   case Instruction::URem:
     105             :   case Instruction::Shl:
     106             :   case Instruction::LShr:
     107             :   case Instruction::AShr:
     108             :   case Instruction::And:
     109             :   case Instruction::Or:
     110             :   case Instruction::Xor:
     111         156 :     return {Weight, {anyIntType(), matchFirstType()}, buildOp};
     112          20 :   case Instruction::FAdd:
     113             :   case Instruction::FSub:
     114             :   case Instruction::FMul:
     115             :   case Instruction::FDiv:
     116             :   case Instruction::FRem:
     117          60 :     return {Weight, {anyFloatType(), matchFirstType()}, buildOp};
     118           0 :   case Instruction::BinaryOpsEnd:
     119           0 :     llvm_unreachable("Value out of range of enum");
     120             :   }
     121           0 :   llvm_unreachable("Covered switch");
     122             : }
     123             : 
     124         104 : OpDescriptor llvm::fuzzerop::cmpOpDescriptor(unsigned Weight,
     125             :                                              Instruction::OtherOps CmpOp,
     126             :                                              CmpInst::Predicate Pred) {
     127           0 :   auto buildOp = [CmpOp, Pred](ArrayRef<Value *> Srcs, Instruction *Inst) {
     128           0 :     return CmpInst::Create(CmpOp, Pred, Srcs[0], Srcs[1], "C", Inst);
     129         104 :   };
     130             : 
     131         104 :   switch (CmpOp) {
     132          40 :   case Instruction::ICmp:
     133         120 :     return {Weight, {anyIntType(), matchFirstType()}, buildOp};
     134          64 :   case Instruction::FCmp:
     135         192 :     return {Weight, {anyFloatType(), matchFirstType()}, buildOp};
     136           0 :   default:
     137           0 :     llvm_unreachable("CmpOp must be ICmp or FCmp");
     138             :   }
     139             : }
     140             : 
     141           6 : OpDescriptor llvm::fuzzerop::splitBlockDescriptor(unsigned Weight) {
     142           3 :   auto buildSplitBlock = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
     143           3 :     BasicBlock *Block = Inst->getParent();
     144           6 :     BasicBlock *Next = Block->splitBasicBlock(Inst, "BB");
     145           6 :     if (Block != &Block->getParent()->getEntryBlock()) {
     146             :       // Loop back on this block by replacing the unconditional forward branch
     147             :       // with a conditional with a backedge.
     148           2 :       BranchInst::Create(Block, Next, Srcs[0], Block->getTerminator());
     149           2 :       Block->getTerminator()->eraseFromParent();
     150             : 
     151             :       // We need values for each phi in the block. Since there isn't a good way
     152             :       // to do a variable number of input values currently, we just fill them
     153             :       // with undef.
     154           6 :       for (PHINode &PHI : Block->phis())
     155           2 :         PHI.addIncoming(UndefValue::get(PHI.getType()), Block);
     156             :     }
     157           3 :     return nullptr;
     158             :   };
     159             :   SourcePred isInt1Ty{[](ArrayRef<Value *>, const Value *V) {
     160           0 :                         return V->getType()->isIntegerTy(1);
     161           0 :                       },
     162          24 :                       None};
     163          24 :   return {Weight, {isInt1Ty}, buildSplitBlock};
     164             : }
     165             : 
     166           5 : OpDescriptor llvm::fuzzerop::gepDescriptor(unsigned Weight) {
     167           1 :   auto buildGEP = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
     168           2 :     Type *Ty = cast<PointerType>(Srcs[0]->getType())->getElementType();
     169           2 :     auto Indices = makeArrayRef(Srcs).drop_front(1);
     170           1 :     return GetElementPtrInst::Create(Ty, Srcs[0], Indices, "G", Inst);
     171             :   };
     172             :   // TODO: Handle aggregates and vectors
     173             :   // TODO: Support multiple indices.
     174             :   // TODO: Try to avoid meaningless accesses.
     175          15 :   return {Weight, {anyPtrType(), anyIntType()}, buildGEP};
     176             : }
     177             : 
     178             : static uint64_t getAggregateNumElements(Type *T) {
     179             :   assert(T->isAggregateType() && "Not a struct or array");
     180          20 :   if (isa<StructType>(T))
     181          14 :     return T->getStructNumElements();
     182           6 :   return T->getArrayNumElements();
     183             : }
     184             : 
     185           5 : static SourcePred validExtractValueIndex() {
     186           8 :   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
     187           8 :     if (auto *CI = dyn_cast<ConstantInt>(V))
     188          24 :       if (!CI->uge(getAggregateNumElements(Cur[0]->getType())))
     189             :         return true;
     190             :     return false;
     191             :   };
     192           1 :   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> Ts) {
     193           1 :     std::vector<Constant *> Result;
     194           1 :     auto *Int32Ty = Type::getInt32Ty(Cur[0]->getContext());
     195           2 :     uint64_t N = getAggregateNumElements(Cur[0]->getType());
     196             :     // Create indices at the start, end, and middle, but avoid dups.
     197           2 :     Result.push_back(ConstantInt::get(Int32Ty, 0));
     198           1 :     if (N > 1)
     199           2 :       Result.push_back(ConstantInt::get(Int32Ty, N - 1));
     200           1 :     if (N > 2)
     201           0 :       Result.push_back(ConstantInt::get(Int32Ty, N / 2));
     202           1 :     return Result;
     203             :   };
     204          25 :   return {Pred, Make};
     205             : }
     206             : 
     207           5 : OpDescriptor llvm::fuzzerop::extractValueDescriptor(unsigned Weight) {
     208           0 :   auto buildExtract = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
     209             :     // TODO: It's pretty inefficient to shuffle this all through constants.
     210           0 :     unsigned Idx = cast<ConstantInt>(Srcs[1])->getZExtValue();
     211           0 :     return ExtractValueInst::Create(Srcs[0], {Idx}, "E", Inst);
     212             :   };
     213             :   // TODO: Should we handle multiple indices?
     214          15 :   return {Weight, {anyAggregateType(), validExtractValueIndex()}, buildExtract};
     215             : }
     216             : 
     217           5 : static SourcePred matchScalarInAggregate() {
     218           3 :   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
     219           6 :     if (isa<ArrayType>(Cur[0]->getType()))
     220           0 :       return V->getType() == Cur[0]->getType();
     221           6 :     auto *STy = cast<StructType>(Cur[0]->getType());
     222           6 :     for (int I = 0, E = STy->getNumElements(); I < E; ++I)
     223           5 :       if (STy->getTypeAtIndex(I) == V->getType())
     224             :         return true;
     225             :     return false;
     226             :   };
     227           1 :   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
     228           2 :     if (isa<ArrayType>(Cur[0]->getType()))
     229           0 :       return makeConstantsWithType(Cur[0]->getType());
     230           1 :     std::vector<Constant *> Result;
     231           2 :     auto *STy = cast<StructType>(Cur[0]->getType());
     232           3 :     for (int I = 0, E = STy->getNumElements(); I < E; ++I)
     233           2 :       makeConstantsWithType(STy->getTypeAtIndex(I), Result);
     234           1 :     return Result;
     235             :   };
     236          25 :   return {Pred, Make};
     237             : }
     238             : 
     239           5 : static SourcePred validInsertValueIndex() {
     240           2 :   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
     241           4 :     auto *CTy = cast<CompositeType>(Cur[0]->getType());
     242           2 :     if (auto *CI = dyn_cast<ConstantInt>(V))
     243           2 :       if (CI->getBitWidth() == 32)
     244           2 :         if (CTy->getTypeAtIndex(CI->getZExtValue()) == V->getType())
     245             :           return true;
     246             :     return false;
     247             :   };
     248           1 :   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> Ts) {
     249           1 :     std::vector<Constant *> Result;
     250           1 :     auto *Int32Ty = Type::getInt32Ty(Cur[0]->getContext());
     251           2 :     auto *CTy = cast<CompositeType>(Cur[0]->getType());
     252           4 :     for (int I = 0, E = getAggregateNumElements(CTy); I < E; ++I)
     253           2 :       if (CTy->getTypeAtIndex(I) == Cur[1]->getType())
     254           2 :         Result.push_back(ConstantInt::get(Int32Ty, I));
     255           1 :     return Result;
     256             :   };
     257          25 :   return {Pred, Make};
     258             : }
     259             : 
     260           5 : OpDescriptor llvm::fuzzerop::insertValueDescriptor(unsigned Weight) {
     261           0 :   auto buildInsert = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
     262             :     // TODO: It's pretty inefficient to shuffle this all through constants.
     263           0 :     unsigned Idx = cast<ConstantInt>(Srcs[2])->getZExtValue();
     264           0 :     return InsertValueInst::Create(Srcs[0], Srcs[1], {Idx}, "I", Inst);
     265             :   };
     266             :   return {
     267             :       Weight,
     268             :       {anyAggregateType(), matchScalarInAggregate(), validInsertValueIndex()},
     269          15 :       buildInsert};
     270             : }
     271             : 
     272           4 : OpDescriptor llvm::fuzzerop::extractElementDescriptor(unsigned Weight) {
     273           0 :   auto buildExtract = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
     274           0 :     return ExtractElementInst::Create(Srcs[0], Srcs[1], "E", Inst);
     275           0 :   };
     276             :   // TODO: Try to avoid undefined accesses.
     277          12 :   return {Weight, {anyVectorType(), anyIntType()}, buildExtract};
     278             : }
     279             : 
     280           4 : OpDescriptor llvm::fuzzerop::insertElementDescriptor(unsigned Weight) {
     281           0 :   auto buildInsert = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
     282           0 :     return InsertElementInst::Create(Srcs[0], Srcs[1], Srcs[2], "I", Inst);
     283           0 :   };
     284             :     // TODO: Try to avoid undefined accesses.
     285             :   return {Weight,
     286             :           {anyVectorType(), matchScalarOfFirstType(), anyIntType()},
     287          12 :           buildInsert};
     288             : }
     289             : 
     290           4 : static SourcePred validShuffleVectorIndex() {
     291             :   auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
     292           0 :     return ShuffleVectorInst::isValidOperands(Cur[0], Cur[1], V);
     293           0 :   };
     294           0 :   auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> Ts) {
     295           0 :     auto *FirstTy = cast<VectorType>(Cur[0]->getType());
     296           0 :     auto *Int32Ty = Type::getInt32Ty(Cur[0]->getContext());
     297             :     // TODO: It's straighforward to make up reasonable values, but listing them
     298             :     // exhaustively would be insane. Come up with a couple of sensible ones.
     299             :     return std::vector<Constant *>{
     300           0 :         UndefValue::get(VectorType::get(Int32Ty, FirstTy->getNumElements()))};
     301             :   };
     302          20 :   return {Pred, Make};
     303             : }
     304             : 
     305           4 : OpDescriptor llvm::fuzzerop::shuffleVectorDescriptor(unsigned Weight) {
     306           0 :   auto buildShuffle = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
     307           0 :     return new ShuffleVectorInst(Srcs[0], Srcs[1], Srcs[2], "S", Inst);
     308           0 :   };
     309             :   return {Weight,
     310             :           {anyVectorType(), matchFirstType(), validShuffleVectorIndex()},
     311          12 :           buildShuffle};
     312             : }

Generated by: LCOV version 1.13