Operations.cpp 13 KB

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