fuzzer_pass_add_useful_constructs.cpp 9.5 KB

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