validate_datarules.cpp 11 KB

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