validate_datarules.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. // Copyright (c) 2016 Google Inc.
  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. // Ensures Data Rules are followed according to the specifications.
  15. #include "validate.h"
  16. #include <cassert>
  17. #include <sstream>
  18. #include <string>
  19. #include "diagnostic.h"
  20. #include "opcode.h"
  21. #include "operand.h"
  22. #include "val/instruction.h"
  23. #include "val/validation_state.h"
  24. using libspirv::CapabilitySet;
  25. using libspirv::DiagnosticStream;
  26. using libspirv::ValidationState_t;
  27. namespace {
  28. // Validates that the number of components in the vector is valid.
  29. // Vector types can only be parameterized as having 2, 3, or 4 components.
  30. // If the Vector16 capability is added, 8 and 16 components are also allowed.
  31. spv_result_t ValidateVecNumComponents(ValidationState_t& _,
  32. const spv_parsed_instruction_t* inst) {
  33. // Operand 2 specifies the number of components in the vector.
  34. const uint32_t num_components = inst->words[inst->operands[2].offset];
  35. if (num_components == 2 || num_components == 3 || num_components == 4) {
  36. return SPV_SUCCESS;
  37. }
  38. if (num_components == 8 || num_components == 16) {
  39. if (_.HasCapability(SpvCapabilityVector16)) {
  40. return SPV_SUCCESS;
  41. }
  42. return _.diag(SPV_ERROR_INVALID_DATA)
  43. << "Having " << num_components << " components for "
  44. << spvOpcodeString(static_cast<SpvOp>(inst->opcode))
  45. << " requires the Vector16 capability";
  46. }
  47. return _.diag(SPV_ERROR_INVALID_DATA)
  48. << "Illegal number of components (" << num_components << ") for "
  49. << spvOpcodeString(static_cast<SpvOp>(inst->opcode));
  50. }
  51. // Validates that the number of bits specifed for a float type is valid.
  52. // Scalar floating-point types can be parameterized only with 32-bits.
  53. // Float16 capability allows using a 16-bit OpTypeFloat.
  54. // Float16Buffer capability allows creation of a 16-bit OpTypeFloat.
  55. // Float64 capability allows using a 64-bit OpTypeFloat.
  56. spv_result_t ValidateFloatSize(ValidationState_t& _,
  57. const spv_parsed_instruction_t* inst) {
  58. // Operand 1 is the number of bits for this float
  59. const uint32_t num_bits = inst->words[inst->operands[1].offset];
  60. if (num_bits == 32) {
  61. return SPV_SUCCESS;
  62. }
  63. if (num_bits == 16) {
  64. if (_.features().declare_float16_type) {
  65. return SPV_SUCCESS;
  66. }
  67. return _.diag(SPV_ERROR_INVALID_DATA)
  68. << "Using a 16-bit floating point "
  69. << "type requires the Float16 or Float16Buffer capability,"
  70. " or an extension that explicitly enables 16-bit floating point.";
  71. }
  72. if (num_bits == 64) {
  73. if (_.HasCapability(SpvCapabilityFloat64)) {
  74. return SPV_SUCCESS;
  75. }
  76. return _.diag(SPV_ERROR_INVALID_DATA)
  77. << "Using a 64-bit floating point "
  78. << "type requires the Float64 capability.";
  79. }
  80. return _.diag(SPV_ERROR_INVALID_DATA)
  81. << "Invalid number of bits (" << num_bits << ") used for OpTypeFloat.";
  82. }
  83. // Validates that the number of bits specified for an Int type is valid.
  84. // Scalar integer types can be parameterized only with 32-bits.
  85. // Int8, Int16, and Int64 capabilities allow using 8-bit, 16-bit, and 64-bit
  86. // integers, respectively.
  87. spv_result_t ValidateIntSize(ValidationState_t& _,
  88. const spv_parsed_instruction_t* inst) {
  89. // Operand 1 is the number of bits for this integer.
  90. const uint32_t num_bits = inst->words[inst->operands[1].offset];
  91. if (num_bits == 32) {
  92. return SPV_SUCCESS;
  93. }
  94. if (num_bits == 8) {
  95. if (_.HasCapability(SpvCapabilityInt8)) {
  96. return SPV_SUCCESS;
  97. }
  98. return _.diag(SPV_ERROR_INVALID_DATA)
  99. << "Using an 8-bit integer type requires the Int8 capability.";
  100. }
  101. if (num_bits == 16) {
  102. if (_.features().declare_int16_type) {
  103. return SPV_SUCCESS;
  104. }
  105. return _.diag(SPV_ERROR_INVALID_DATA)
  106. << "Using a 16-bit integer type requires the Int16 capability,"
  107. " or an extension that explicitly enables 16-bit integers.";
  108. }
  109. if (num_bits == 64) {
  110. if (_.HasCapability(SpvCapabilityInt64)) {
  111. return SPV_SUCCESS;
  112. }
  113. return _.diag(SPV_ERROR_INVALID_DATA)
  114. << "Using a 64-bit integer type requires the Int64 capability.";
  115. }
  116. return _.diag(SPV_ERROR_INVALID_DATA)
  117. << "Invalid number of bits (" << num_bits << ") used for OpTypeInt.";
  118. }
  119. // Validates that the matrix is parameterized with floating-point types.
  120. spv_result_t ValidateMatrixColumnType(ValidationState_t& _,
  121. const spv_parsed_instruction_t* inst) {
  122. // Find the component type of matrix columns (must be vector).
  123. // Operand 1 is the <id> of the type specified for matrix columns.
  124. auto type_id = inst->words[inst->operands[1].offset];
  125. auto col_type_instr = _.FindDef(type_id);
  126. if (col_type_instr->opcode() != SpvOpTypeVector) {
  127. return _.diag(SPV_ERROR_INVALID_ID)
  128. << "Columns in a matrix must be of type vector.";
  129. }
  130. // Trace back once more to find out the type of components in the vector.
  131. // Operand 1 is the <id> of the type of data in the vector.
  132. auto comp_type_id =
  133. col_type_instr->words()[col_type_instr->operands()[1].offset];
  134. auto comp_type_instruction = _.FindDef(comp_type_id);
  135. if (comp_type_instruction->opcode() != SpvOpTypeFloat) {
  136. return _.diag(SPV_ERROR_INVALID_DATA) << "Matrix types can only be "
  137. "parameterized with "
  138. "floating-point types.";
  139. }
  140. return SPV_SUCCESS;
  141. }
  142. // Validates that the matrix has 2,3, or 4 columns.
  143. spv_result_t ValidateMatrixNumCols(ValidationState_t& _,
  144. const spv_parsed_instruction_t* inst) {
  145. // Operand 2 is the number of columns in the matrix.
  146. const uint32_t num_cols = inst->words[inst->operands[2].offset];
  147. if (num_cols != 2 && num_cols != 3 && num_cols != 4) {
  148. return _.diag(SPV_ERROR_INVALID_DATA) << "Matrix types can only be "
  149. "parameterized as having only 2, "
  150. "3, or 4 columns.";
  151. }
  152. return SPV_SUCCESS;
  153. }
  154. // Validates that OpSpecConstant specializes to either int or float type.
  155. spv_result_t ValidateSpecConstNumerical(ValidationState_t& _,
  156. const spv_parsed_instruction_t* inst) {
  157. // Operand 0 is the <id> of the type that we're specializing to.
  158. auto type_id = inst->words[inst->operands[0].offset];
  159. auto type_instruction = _.FindDef(type_id);
  160. auto type_opcode = type_instruction->opcode();
  161. if (type_opcode != SpvOpTypeInt && type_opcode != SpvOpTypeFloat) {
  162. return _.diag(SPV_ERROR_INVALID_DATA) << "Specialization constant must be "
  163. "an integer or floating-point "
  164. "number.";
  165. }
  166. return SPV_SUCCESS;
  167. }
  168. // Validates that OpSpecConstantTrue and OpSpecConstantFalse specialize to bool.
  169. spv_result_t ValidateSpecConstBoolean(ValidationState_t& _,
  170. const spv_parsed_instruction_t* inst) {
  171. // Find out the type that we're specializing to.
  172. auto type_instruction = _.FindDef(inst->type_id);
  173. if (type_instruction->opcode() != SpvOpTypeBool) {
  174. return _.diag(SPV_ERROR_INVALID_ID) << "Specialization constant must be "
  175. "a boolean type.";
  176. }
  177. return SPV_SUCCESS;
  178. }
  179. // Records the <id> of the forward pointer to be used for validation.
  180. spv_result_t ValidateForwardPointer(ValidationState_t& _,
  181. const spv_parsed_instruction_t* inst) {
  182. // Record the <id> (which is operand 0) to ensure it's used properly.
  183. // OpTypeStruct can only include undefined pointers that are
  184. // previously declared as a ForwardPointer
  185. return (_.RegisterForwardPointer(inst->words[inst->operands[0].offset]));
  186. }
  187. // Validates that any undefined component of the struct is a forward pointer.
  188. // It is valid to declare a forward pointer, and use its <id> as one of the
  189. // components of a struct.
  190. spv_result_t ValidateStruct(ValidationState_t& _,
  191. const spv_parsed_instruction_t* inst) {
  192. // Struct components are operands 1, 2, etc.
  193. for (unsigned i = 1; i < inst->num_operands; i++) {
  194. auto type_id = inst->words[inst->operands[i].offset];
  195. auto type_instruction = _.FindDef(type_id);
  196. if (type_instruction == nullptr && !_.IsForwardPointer(type_id)) {
  197. return _.diag(SPV_ERROR_INVALID_ID)
  198. << "Forward reference operands in an OpTypeStruct must first be "
  199. "declared using OpTypeForwardPointer.";
  200. }
  201. }
  202. return SPV_SUCCESS;
  203. }
  204. } // anonymous namespace
  205. namespace libspirv {
  206. // Validates that Data Rules are followed according to the specifications.
  207. // (Data Rules subsection of 2.16.1 Universal Validation Rules)
  208. spv_result_t DataRulesPass(ValidationState_t& _,
  209. const spv_parsed_instruction_t* inst) {
  210. switch (inst->opcode) {
  211. case SpvOpTypeVector: {
  212. if (auto error = ValidateVecNumComponents(_, inst)) return error;
  213. break;
  214. }
  215. case SpvOpTypeFloat: {
  216. if (auto error = ValidateFloatSize(_, inst)) return error;
  217. break;
  218. }
  219. case SpvOpTypeInt: {
  220. if (auto error = ValidateIntSize(_, inst)) return error;
  221. break;
  222. }
  223. case SpvOpTypeMatrix: {
  224. if (auto error = ValidateMatrixColumnType(_, inst)) return error;
  225. if (auto error = ValidateMatrixNumCols(_, inst)) return error;
  226. break;
  227. }
  228. // TODO(ehsan): Add OpSpecConstantComposite validation code.
  229. // TODO(ehsan): Add OpSpecConstantOp validation code (if any).
  230. case SpvOpSpecConstant: {
  231. if (auto error = ValidateSpecConstNumerical(_, inst)) return error;
  232. break;
  233. }
  234. case SpvOpSpecConstantFalse:
  235. case SpvOpSpecConstantTrue: {
  236. if (auto error = ValidateSpecConstBoolean(_, inst)) return error;
  237. break;
  238. }
  239. case SpvOpTypeForwardPointer: {
  240. if (auto error = ValidateForwardPointer(_, inst)) return error;
  241. break;
  242. }
  243. case SpvOpTypeStruct: {
  244. if (auto error = ValidateStruct(_, inst)) return error;
  245. break;
  246. }
  247. // TODO(ehsan): add more data rules validation here.
  248. default: { break; }
  249. }
  250. return SPV_SUCCESS;
  251. }
  252. } // namespace libspirv