OpDescriptor.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===-- OpDescriptor.h ------------------------------------------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // Provides the fuzzerop::Descriptor class and related tools for describing
  15. // operations an IR fuzzer can work with.
  16. //
  17. //===----------------------------------------------------------------------===//
  18. #ifndef LLVM_FUZZMUTATE_OPDESCRIPTOR_H
  19. #define LLVM_FUZZMUTATE_OPDESCRIPTOR_H
  20. #include "llvm/ADT/ArrayRef.h"
  21. #include "llvm/ADT/SmallVector.h"
  22. #include "llvm/IR/Constants.h"
  23. #include "llvm/IR/DerivedTypes.h"
  24. #include "llvm/IR/Type.h"
  25. #include "llvm/IR/Value.h"
  26. #include <functional>
  27. namespace llvm {
  28. class Instruction;
  29. namespace fuzzerop {
  30. /// @{
  31. /// Populate a small list of potentially interesting constants of a given type.
  32. void makeConstantsWithType(Type *T, std::vector<Constant *> &Cs);
  33. std::vector<Constant *> makeConstantsWithType(Type *T);
  34. /// @}
  35. /// A matcher/generator for finding suitable values for the next source in an
  36. /// operation's partially completed argument list.
  37. ///
  38. /// Given that we're building some operation X and may have already filled some
  39. /// subset of its operands, this predicate determines if some value New is
  40. /// suitable for the next operand or generates a set of values that are
  41. /// suitable.
  42. class SourcePred {
  43. public:
  44. /// Given a list of already selected operands, returns whether a given new
  45. /// operand is suitable for the next operand.
  46. using PredT = std::function<bool(ArrayRef<Value *> Cur, const Value *New)>;
  47. /// Given a list of already selected operands and a set of valid base types
  48. /// for a fuzzer, generates a list of constants that could be used for the
  49. /// next operand.
  50. using MakeT = std::function<std::vector<Constant *>(
  51. ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes)>;
  52. private:
  53. PredT Pred;
  54. MakeT Make;
  55. public:
  56. /// Create a fully general source predicate.
  57. SourcePred(PredT Pred, MakeT Make) : Pred(Pred), Make(Make) {}
  58. SourcePred(PredT Pred, std::nullopt_t) : Pred(Pred) {
  59. Make = [Pred](ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes) {
  60. // Default filter just calls Pred on each of the base types.
  61. std::vector<Constant *> Result;
  62. for (Type *T : BaseTypes) {
  63. Constant *V = UndefValue::get(T);
  64. if (Pred(Cur, V))
  65. makeConstantsWithType(T, Result);
  66. }
  67. if (Result.empty())
  68. report_fatal_error("Predicate does not match for base types");
  69. return Result;
  70. };
  71. }
  72. /// Returns true if \c New is compatible for the argument after \c Cur
  73. bool matches(ArrayRef<Value *> Cur, const Value *New) {
  74. return Pred(Cur, New);
  75. }
  76. /// Generates a list of potential values for the argument after \c Cur.
  77. std::vector<Constant *> generate(ArrayRef<Value *> Cur,
  78. ArrayRef<Type *> BaseTypes) {
  79. return Make(Cur, BaseTypes);
  80. }
  81. };
  82. /// A description of some operation we can build while fuzzing IR.
  83. struct OpDescriptor {
  84. unsigned Weight;
  85. SmallVector<SourcePred, 2> SourcePreds;
  86. std::function<Value *(ArrayRef<Value *>, Instruction *)> BuilderFunc;
  87. };
  88. static inline SourcePred onlyType(Type *Only) {
  89. auto Pred = [Only](ArrayRef<Value *>, const Value *V) {
  90. return V->getType() == Only;
  91. };
  92. auto Make = [Only](ArrayRef<Value *>, ArrayRef<Type *>) {
  93. return makeConstantsWithType(Only);
  94. };
  95. return {Pred, Make};
  96. }
  97. static inline SourcePred anyType() {
  98. auto Pred = [](ArrayRef<Value *>, const Value *V) {
  99. return !V->getType()->isVoidTy();
  100. };
  101. auto Make = std::nullopt;
  102. return {Pred, Make};
  103. }
  104. static inline SourcePred anyIntType() {
  105. auto Pred = [](ArrayRef<Value *>, const Value *V) {
  106. return V->getType()->isIntegerTy();
  107. };
  108. auto Make = std::nullopt;
  109. return {Pred, Make};
  110. }
  111. static inline SourcePred anyFloatType() {
  112. auto Pred = [](ArrayRef<Value *>, const Value *V) {
  113. return V->getType()->isFloatingPointTy();
  114. };
  115. auto Make = std::nullopt;
  116. return {Pred, Make};
  117. }
  118. static inline SourcePred anyPtrType() {
  119. auto Pred = [](ArrayRef<Value *>, const Value *V) {
  120. return V->getType()->isPointerTy() && !V->isSwiftError();
  121. };
  122. auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) {
  123. std::vector<Constant *> Result;
  124. // TODO: Should these point at something?
  125. for (Type *T : Ts)
  126. Result.push_back(UndefValue::get(PointerType::getUnqual(T)));
  127. return Result;
  128. };
  129. return {Pred, Make};
  130. }
  131. static inline SourcePred sizedPtrType() {
  132. auto Pred = [](ArrayRef<Value *>, const Value *V) {
  133. if (V->isSwiftError())
  134. return false;
  135. if (const auto *PtrT = dyn_cast<PointerType>(V->getType()))
  136. return PtrT->isOpaque() ||
  137. PtrT->getNonOpaquePointerElementType()->isSized();
  138. return false;
  139. };
  140. auto Make = [](ArrayRef<Value *>, ArrayRef<Type *> Ts) {
  141. std::vector<Constant *> Result;
  142. for (Type *T : Ts)
  143. if (T->isSized())
  144. Result.push_back(UndefValue::get(PointerType::getUnqual(T)));
  145. return Result;
  146. };
  147. return {Pred, Make};
  148. }
  149. static inline SourcePred anyAggregateType() {
  150. auto Pred = [](ArrayRef<Value *>, const Value *V) {
  151. // We can't index zero sized arrays.
  152. if (isa<ArrayType>(V->getType()))
  153. return V->getType()->getArrayNumElements() > 0;
  154. // Structs can also be zero sized. I.e opaque types.
  155. if (isa<StructType>(V->getType()))
  156. return V->getType()->getStructNumElements() > 0;
  157. return V->getType()->isAggregateType();
  158. };
  159. // TODO: For now we only find aggregates in BaseTypes. It might be better to
  160. // manufacture them out of the base types in some cases.
  161. auto Find = std::nullopt;
  162. return {Pred, Find};
  163. }
  164. static inline SourcePred anyVectorType() {
  165. auto Pred = [](ArrayRef<Value *>, const Value *V) {
  166. return V->getType()->isVectorTy();
  167. };
  168. // TODO: For now we only find vectors in BaseTypes. It might be better to
  169. // manufacture vectors out of the base types, but it's tricky to be sure
  170. // that's actually a reasonable type.
  171. auto Make = std::nullopt;
  172. return {Pred, Make};
  173. }
  174. /// Match values that have the same type as the first source.
  175. static inline SourcePred matchFirstType() {
  176. auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
  177. assert(!Cur.empty() && "No first source yet");
  178. return V->getType() == Cur[0]->getType();
  179. };
  180. auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
  181. assert(!Cur.empty() && "No first source yet");
  182. return makeConstantsWithType(Cur[0]->getType());
  183. };
  184. return {Pred, Make};
  185. }
  186. /// Match values that have the first source's scalar type.
  187. static inline SourcePred matchScalarOfFirstType() {
  188. auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
  189. assert(!Cur.empty() && "No first source yet");
  190. return V->getType() == Cur[0]->getType()->getScalarType();
  191. };
  192. auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
  193. assert(!Cur.empty() && "No first source yet");
  194. return makeConstantsWithType(Cur[0]->getType()->getScalarType());
  195. };
  196. return {Pred, Make};
  197. }
  198. } // namespace fuzzerop
  199. } // namespace llvm
  200. #endif // LLVM_FUZZMUTATE_OPDESCRIPTOR_H
  201. #ifdef __GNUC__
  202. #pragma GCC diagnostic pop
  203. #endif