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

Generated by: LCOV version 1.13