transformation_add_global_variable.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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/transformation_add_global_variable.h"
  15. #include "source/fuzz/fuzzer_util.h"
  16. namespace spvtools {
  17. namespace fuzz {
  18. TransformationAddGlobalVariable::TransformationAddGlobalVariable(
  19. const spvtools::fuzz::protobufs::TransformationAddGlobalVariable& message)
  20. : message_(message) {}
  21. TransformationAddGlobalVariable::TransformationAddGlobalVariable(
  22. uint32_t fresh_id, uint32_t type_id, uint32_t initializer_id,
  23. bool value_is_irrelevant) {
  24. message_.set_fresh_id(fresh_id);
  25. message_.set_type_id(type_id);
  26. message_.set_initializer_id(initializer_id);
  27. message_.set_value_is_irrelevant(value_is_irrelevant);
  28. }
  29. bool TransformationAddGlobalVariable::IsApplicable(
  30. opt::IRContext* context,
  31. const spvtools::fuzz::FactManager& /*unused*/) const {
  32. // The result id must be fresh.
  33. if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
  34. return false;
  35. }
  36. // The type id must correspond to a type.
  37. auto type = context->get_type_mgr()->GetType(message_.type_id());
  38. if (!type) {
  39. return false;
  40. }
  41. // That type must be a pointer type ...
  42. auto pointer_type = type->AsPointer();
  43. if (!pointer_type) {
  44. return false;
  45. }
  46. // ... with Private storage class.
  47. if (pointer_type->storage_class() != SpvStorageClassPrivate) {
  48. return false;
  49. }
  50. // The initializer id must be the id of a constant. Check this with the
  51. // constant manager.
  52. auto constant_id = context->get_constant_mgr()->GetConstantsFromIds(
  53. {message_.initializer_id()});
  54. if (constant_id.empty()) {
  55. return false;
  56. }
  57. assert(constant_id.size() == 1 &&
  58. "We asked for the constant associated with a single id; we should "
  59. "get a single constant.");
  60. // The type of the constant must match the pointee type of the pointer.
  61. if (pointer_type->pointee_type() != constant_id[0]->type()) {
  62. return false;
  63. }
  64. return true;
  65. }
  66. void TransformationAddGlobalVariable::Apply(
  67. opt::IRContext* context, spvtools::fuzz::FactManager* fact_manager) const {
  68. opt::Instruction::OperandList input_operands;
  69. input_operands.push_back(
  70. {SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassPrivate}});
  71. if (message_.initializer_id()) {
  72. input_operands.push_back(
  73. {SPV_OPERAND_TYPE_ID, {message_.initializer_id()}});
  74. }
  75. context->module()->AddGlobalValue(
  76. MakeUnique<opt::Instruction>(context, SpvOpVariable, message_.type_id(),
  77. message_.fresh_id(), input_operands));
  78. fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
  79. if (PrivateGlobalsMustBeDeclaredInEntryPointInterfaces(context)) {
  80. // Conservatively add this global to the interface of every entry point in
  81. // the module. This means that the global is available for other
  82. // transformations to use.
  83. //
  84. // A downside of this is that the global will be in the interface even if it
  85. // ends up never being used.
  86. //
  87. // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3111) revisit
  88. // this if a more thorough approach to entry point interfaces is taken.
  89. for (auto& entry_point : context->module()->entry_points()) {
  90. entry_point.AddOperand({SPV_OPERAND_TYPE_ID, {message_.fresh_id()}});
  91. }
  92. }
  93. if (message_.value_is_irrelevant()) {
  94. fact_manager->AddFactValueOfPointeeIsIrrelevant(message_.fresh_id());
  95. }
  96. // We have added an instruction to the module, so need to be careful about the
  97. // validity of existing analyses.
  98. context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
  99. }
  100. protobufs::Transformation TransformationAddGlobalVariable::ToMessage() const {
  101. protobufs::Transformation result;
  102. *result.mutable_add_global_variable() = message_;
  103. return result;
  104. }
  105. bool TransformationAddGlobalVariable::
  106. PrivateGlobalsMustBeDeclaredInEntryPointInterfaces(
  107. opt::IRContext* context) {
  108. // TODO(afd): We capture the universal environments for which this requirement
  109. // holds. The check should be refined on demand for other target
  110. // environments.
  111. switch (context->grammar().target_env()) {
  112. case SPV_ENV_UNIVERSAL_1_0:
  113. case SPV_ENV_UNIVERSAL_1_1:
  114. case SPV_ENV_UNIVERSAL_1_2:
  115. case SPV_ENV_UNIVERSAL_1_3:
  116. return false;
  117. default:
  118. return true;
  119. }
  120. }
  121. } // namespace fuzz
  122. } // namespace spvtools