validate_non_uniform.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // Copyright (c) 2018 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. // Validates correctness of barrier SPIR-V instructions.
  15. #include "source/val/validate.h"
  16. #include "source/diagnostic.h"
  17. #include "source/opcode.h"
  18. #include "source/spirv_constant.h"
  19. #include "source/spirv_target_env.h"
  20. #include "source/util/bitutils.h"
  21. #include "source/val/instruction.h"
  22. #include "source/val/validate_scopes.h"
  23. #include "source/val/validation_state.h"
  24. namespace spvtools {
  25. namespace val {
  26. namespace {
  27. spv_result_t ValidateGroupNonUniformBallotBitCount(ValidationState_t& _,
  28. const Instruction* inst) {
  29. // Scope is already checked by ValidateExecutionScope() above.
  30. const uint32_t result_type = inst->type_id();
  31. if (!_.IsUnsignedIntScalarType(result_type)) {
  32. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  33. << "Expected Result Type to be an unsigned integer type scalar.";
  34. }
  35. const auto value = inst->GetOperandAs<uint32_t>(4);
  36. const auto value_type = _.FindDef(value)->type_id();
  37. if (!_.IsUnsignedIntVectorType(value_type) ||
  38. _.GetDimension(value_type) != 4) {
  39. return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Value to be a "
  40. "vector of four components "
  41. "of integer type scalar";
  42. }
  43. const auto group = inst->GetOperandAs<uint32_t>(3);
  44. if (spvIsVulkanEnv(_.context()->target_env)) {
  45. if ((group != SpvGroupOperationReduce) &&
  46. (group != SpvGroupOperationInclusiveScan) &&
  47. (group != SpvGroupOperationExclusiveScan)) {
  48. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  49. << _.VkErrorID(4685)
  50. << "In Vulkan: The OpGroupNonUniformBallotBitCount group "
  51. "operation must be only: Reduce, InclusiveScan, or "
  52. "ExclusiveScan.";
  53. }
  54. }
  55. return SPV_SUCCESS;
  56. }
  57. spv_result_t ValidateGroupNonUniformRotateKHR(ValidationState_t& _,
  58. const Instruction* inst) {
  59. // Scope is already checked by ValidateExecutionScope() above.
  60. const uint32_t result_type = inst->type_id();
  61. if (!_.IsIntScalarOrVectorType(result_type) &&
  62. !_.IsFloatScalarOrVectorType(result_type) &&
  63. !_.IsBoolScalarOrVectorType(result_type)) {
  64. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  65. << "Expected Result Type to be a scalar or vector of "
  66. "floating-point, integer or boolean type.";
  67. }
  68. const uint32_t value_type = _.GetTypeId(inst->GetOperandAs<uint32_t>(3));
  69. if (value_type != result_type) {
  70. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  71. << "Result Type must be the same as the type of Value.";
  72. }
  73. const uint32_t delta_type = _.GetTypeId(inst->GetOperandAs<uint32_t>(4));
  74. if (!_.IsUnsignedIntScalarType(delta_type)) {
  75. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  76. << "Delta must be a scalar of integer type, whose Signedness "
  77. "operand is 0.";
  78. }
  79. if (inst->words().size() > 6) {
  80. const uint32_t cluster_size_op_id = inst->GetOperandAs<uint32_t>(5);
  81. const uint32_t cluster_size_type = _.GetTypeId(cluster_size_op_id);
  82. if (!_.IsUnsignedIntScalarType(cluster_size_type)) {
  83. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  84. << "ClusterSize must be a scalar of integer type, whose "
  85. "Signedness operand is 0.";
  86. }
  87. uint64_t cluster_size;
  88. if (!_.GetConstantValUint64(cluster_size_op_id, &cluster_size)) {
  89. return _.diag(SPV_ERROR_INVALID_DATA, inst)
  90. << "ClusterSize must come from a constant instruction.";
  91. }
  92. if ((cluster_size == 0) || ((cluster_size & (cluster_size - 1)) != 0)) {
  93. return _.diag(SPV_WARNING, inst)
  94. << "Behavior is undefined unless ClusterSize is at least 1 and a "
  95. "power of 2.";
  96. }
  97. // TODO(kpet) Warn about undefined behavior when ClusterSize is greater than
  98. // the declared SubGroupSize
  99. }
  100. return SPV_SUCCESS;
  101. }
  102. } // namespace
  103. // Validates correctness of non-uniform group instructions.
  104. spv_result_t NonUniformPass(ValidationState_t& _, const Instruction* inst) {
  105. const SpvOp opcode = inst->opcode();
  106. if (spvOpcodeIsNonUniformGroupOperation(opcode)) {
  107. const uint32_t execution_scope = inst->word(3);
  108. if (auto error = ValidateExecutionScope(_, inst, execution_scope)) {
  109. return error;
  110. }
  111. }
  112. switch (opcode) {
  113. case SpvOpGroupNonUniformBallotBitCount:
  114. return ValidateGroupNonUniformBallotBitCount(_, inst);
  115. case SpvOpGroupNonUniformRotateKHR:
  116. return ValidateGroupNonUniformRotateKHR(_, inst);
  117. default:
  118. break;
  119. }
  120. return SPV_SUCCESS;
  121. }
  122. } // namespace val
  123. } // namespace spvtools