fuzzer_pass_add_useful_constructs.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Copyright (c) 2019 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "source/fuzz/fuzzer_pass_add_useful_constructs.h"
  15. #include "source/fuzz/transformation_add_constant_boolean.h"
  16. #include "source/fuzz/transformation_add_constant_scalar.h"
  17. #include "source/fuzz/transformation_add_type_boolean.h"
  18. #include "source/fuzz/transformation_add_type_float.h"
  19. #include "source/fuzz/transformation_add_type_int.h"
  20. #include "source/fuzz/transformation_add_type_pointer.h"
  21. namespace spvtools {
  22. namespace fuzz {
  23. using opt::IRContext;
  24. FuzzerPassAddUsefulConstructs::FuzzerPassAddUsefulConstructs(
  25. opt::IRContext* ir_context, FactManager* fact_manager,
  26. FuzzerContext* fuzzer_context,
  27. protobufs::TransformationSequence* transformations)
  28. : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations){};
  29. FuzzerPassAddUsefulConstructs::~FuzzerPassAddUsefulConstructs() = default;
  30. void FuzzerPassAddUsefulConstructs::MaybeAddIntConstant(
  31. uint32_t width, bool is_signed, std::vector<uint32_t> data) const {
  32. opt::analysis::Integer temp_int_type(width, is_signed);
  33. assert(GetIRContext()->get_type_mgr()->GetId(&temp_int_type) &&
  34. "int type should already be registered.");
  35. auto registered_int_type = GetIRContext()
  36. ->get_type_mgr()
  37. ->GetRegisteredType(&temp_int_type)
  38. ->AsInteger();
  39. auto int_type_id = GetIRContext()->get_type_mgr()->GetId(registered_int_type);
  40. assert(int_type_id &&
  41. "The relevant int type should have been added to the module already.");
  42. opt::analysis::IntConstant int_constant(registered_int_type, data);
  43. if (!GetIRContext()->get_constant_mgr()->FindConstant(&int_constant)) {
  44. TransformationAddConstantScalar add_constant_int =
  45. TransformationAddConstantScalar(GetFuzzerContext()->GetFreshId(),
  46. int_type_id, data);
  47. assert(add_constant_int.IsApplicable(GetIRContext(), *GetFactManager()) &&
  48. "Should be applicable by construction.");
  49. add_constant_int.Apply(GetIRContext(), GetFactManager());
  50. *GetTransformations()->add_transformation() = add_constant_int.ToMessage();
  51. }
  52. }
  53. void FuzzerPassAddUsefulConstructs::MaybeAddFloatConstant(
  54. uint32_t width, std::vector<uint32_t> data) const {
  55. opt::analysis::Float temp_float_type(width);
  56. assert(GetIRContext()->get_type_mgr()->GetId(&temp_float_type) &&
  57. "float type should already be registered.");
  58. auto registered_float_type = GetIRContext()
  59. ->get_type_mgr()
  60. ->GetRegisteredType(&temp_float_type)
  61. ->AsFloat();
  62. auto float_type_id =
  63. GetIRContext()->get_type_mgr()->GetId(registered_float_type);
  64. assert(
  65. float_type_id &&
  66. "The relevant float type should have been added to the module already.");
  67. opt::analysis::FloatConstant float_constant(registered_float_type, data);
  68. if (!GetIRContext()->get_constant_mgr()->FindConstant(&float_constant)) {
  69. TransformationAddConstantScalar add_constant_float =
  70. TransformationAddConstantScalar(GetFuzzerContext()->GetFreshId(),
  71. float_type_id, data);
  72. assert(add_constant_float.IsApplicable(GetIRContext(), *GetFactManager()) &&
  73. "Should be applicable by construction.");
  74. add_constant_float.Apply(GetIRContext(), GetFactManager());
  75. *GetTransformations()->add_transformation() =
  76. add_constant_float.ToMessage();
  77. }
  78. }
  79. void FuzzerPassAddUsefulConstructs::Apply() {
  80. {
  81. // Add boolean type if not present.
  82. opt::analysis::Bool temp_bool_type;
  83. if (!GetIRContext()->get_type_mgr()->GetId(&temp_bool_type)) {
  84. auto add_type_boolean =
  85. TransformationAddTypeBoolean(GetFuzzerContext()->GetFreshId());
  86. assert(add_type_boolean.IsApplicable(GetIRContext(), *GetFactManager()) &&
  87. "Should be applicable by construction.");
  88. add_type_boolean.Apply(GetIRContext(), GetFactManager());
  89. *GetTransformations()->add_transformation() =
  90. add_type_boolean.ToMessage();
  91. }
  92. }
  93. {
  94. // Add signed and unsigned 32-bit integer types if not present.
  95. for (auto is_signed : {true, false}) {
  96. opt::analysis::Integer temp_int_type(32, is_signed);
  97. if (!GetIRContext()->get_type_mgr()->GetId(&temp_int_type)) {
  98. TransformationAddTypeInt add_type_int = TransformationAddTypeInt(
  99. GetFuzzerContext()->GetFreshId(), 32, is_signed);
  100. assert(add_type_int.IsApplicable(GetIRContext(), *GetFactManager()) &&
  101. "Should be applicable by construction.");
  102. add_type_int.Apply(GetIRContext(), GetFactManager());
  103. *GetTransformations()->add_transformation() = add_type_int.ToMessage();
  104. }
  105. }
  106. }
  107. {
  108. // Add 32-bit float type if not present.
  109. opt::analysis::Float temp_float_type(32);
  110. if (!GetIRContext()->get_type_mgr()->GetId(&temp_float_type)) {
  111. TransformationAddTypeFloat add_type_float =
  112. TransformationAddTypeFloat(GetFuzzerContext()->GetFreshId(), 32);
  113. assert(add_type_float.IsApplicable(GetIRContext(), *GetFactManager()) &&
  114. "Should be applicable by construction.");
  115. add_type_float.Apply(GetIRContext(), GetFactManager());
  116. *GetTransformations()->add_transformation() = add_type_float.ToMessage();
  117. }
  118. }
  119. // Add boolean constants true and false if not present.
  120. opt::analysis::Bool temp_bool_type;
  121. auto bool_type = GetIRContext()
  122. ->get_type_mgr()
  123. ->GetRegisteredType(&temp_bool_type)
  124. ->AsBool();
  125. for (auto boolean_value : {true, false}) {
  126. // Add OpConstantTrue/False if not already there.
  127. opt::analysis::BoolConstant bool_constant(bool_type, boolean_value);
  128. if (!GetIRContext()->get_constant_mgr()->FindConstant(&bool_constant)) {
  129. TransformationAddConstantBoolean add_constant_boolean(
  130. GetFuzzerContext()->GetFreshId(), boolean_value);
  131. assert(add_constant_boolean.IsApplicable(GetIRContext(),
  132. *GetFactManager()) &&
  133. "Should be applicable by construction.");
  134. add_constant_boolean.Apply(GetIRContext(), GetFactManager());
  135. *GetTransformations()->add_transformation() =
  136. add_constant_boolean.ToMessage();
  137. }
  138. }
  139. // Add signed and unsigned 32-bit integer constants 0 and 1 if not present.
  140. for (auto is_signed : {true, false}) {
  141. for (auto value : {0u, 1u}) {
  142. MaybeAddIntConstant(32, is_signed, {value});
  143. }
  144. }
  145. // Add 32-bit float constants 0.0 and 1.0 if not present.
  146. uint32_t uint_data[2];
  147. float float_data[2] = {0.0, 1.0};
  148. memcpy(uint_data, float_data, sizeof(float_data));
  149. for (unsigned int& datum : uint_data) {
  150. MaybeAddFloatConstant(32, {datum});
  151. }
  152. // For every known-to-be-constant uniform, make sure we have instructions
  153. // declaring:
  154. // - a pointer type with uniform storage class, whose pointee type is the type
  155. // of the element
  156. // - a signed integer constant for each index required to access the element
  157. // - a constant for the constant value itself
  158. for (auto& fact_and_type_id :
  159. GetFactManager()->GetConstantUniformFactsAndTypes()) {
  160. uint32_t element_type_id = fact_and_type_id.second;
  161. assert(element_type_id);
  162. auto element_type =
  163. GetIRContext()->get_type_mgr()->GetType(element_type_id);
  164. assert(element_type &&
  165. "If the constant uniform fact is well-formed, the module must "
  166. "already have a declaration of the type for the uniform element.");
  167. opt::analysis::Pointer uniform_pointer(element_type,
  168. SpvStorageClassUniform);
  169. if (!GetIRContext()->get_type_mgr()->GetId(&uniform_pointer)) {
  170. auto add_pointer =
  171. TransformationAddTypePointer(GetFuzzerContext()->GetFreshId(),
  172. SpvStorageClassUniform, element_type_id);
  173. assert(add_pointer.IsApplicable(GetIRContext(), *GetFactManager()) &&
  174. "Should be applicable by construction.");
  175. add_pointer.Apply(GetIRContext(), GetFactManager());
  176. *GetTransformations()->add_transformation() = add_pointer.ToMessage();
  177. }
  178. std::vector<uint32_t> words;
  179. for (auto word : fact_and_type_id.first.constant_word()) {
  180. words.push_back(word);
  181. }
  182. // We get the element type again as the type manager may have been
  183. // invalidated since we last retrieved it.
  184. element_type = GetIRContext()->get_type_mgr()->GetType(element_type_id);
  185. if (element_type->AsInteger()) {
  186. MaybeAddIntConstant(element_type->AsInteger()->width(),
  187. element_type->AsInteger()->IsSigned(), words);
  188. } else {
  189. assert(element_type->AsFloat() &&
  190. "Known uniform values must be integer or floating-point.");
  191. MaybeAddFloatConstant(element_type->AsFloat()->width(), words);
  192. }
  193. for (auto index :
  194. fact_and_type_id.first.uniform_buffer_element_descriptor().index()) {
  195. MaybeAddIntConstant(32, true, {index});
  196. }
  197. }
  198. }
  199. } // namespace fuzz
  200. } // namespace spvtools