Returns SPV_SUCCESS if the given operand is enabled by capabilities declared in the module. Otherwise issues an error message and returns SPV_ERROR_INVALID_CAPABILITY.
| 137 | // in the module. Otherwise issues an error message and returns |
| 138 | // SPV_ERROR_INVALID_CAPABILITY. |
| 139 | spv_result_t CheckRequiredCapabilities(ValidationState_t& state, |
| 140 | const Instruction* inst, |
| 141 | size_t which_operand, |
| 142 | const spv_parsed_operand_t& operand, |
| 143 | uint32_t word) { |
| 144 | // Mere mention of PointSize, ClipDistance, or CullDistance in a Builtin |
| 145 | // decoration does not require the associated capability. The use of such |
| 146 | // a variable value should trigger the capability requirement, but that's |
| 147 | // not implemented yet. This rule is independent of target environment. |
| 148 | // See https://github.com/KhronosGroup/SPIRV-Tools/issues/365 |
| 149 | if (operand.type == SPV_OPERAND_TYPE_BUILT_IN) { |
| 150 | switch (spv::BuiltIn(word)) { |
| 151 | case spv::BuiltIn::PointSize: |
| 152 | case spv::BuiltIn::ClipDistance: |
| 153 | case spv::BuiltIn::CullDistance: |
| 154 | return SPV_SUCCESS; |
| 155 | default: |
| 156 | break; |
| 157 | } |
| 158 | } else if (operand.type == SPV_OPERAND_TYPE_FP_ROUNDING_MODE) { |
| 159 | // Allow all FP rounding modes if requested |
| 160 | if (state.features().free_fp_rounding_mode) { |
| 161 | return SPV_SUCCESS; |
| 162 | } |
| 163 | } else if (operand.type == SPV_OPERAND_TYPE_GROUP_OPERATION && |
| 164 | state.features().group_ops_reduce_and_scans && |
| 165 | (word <= uint32_t(spv::GroupOperation::ExclusiveScan))) { |
| 166 | // Allow certain group operations if requested. |
| 167 | return SPV_SUCCESS; |
| 168 | } |
| 169 | |
| 170 | CapabilitySet enabling_capabilities; |
| 171 | const spvtools::OperandDesc* operand_desc = nullptr; |
| 172 | const auto lookup_result = |
| 173 | spvtools::LookupOperand(operand.type, word, &operand_desc); |
| 174 | if (lookup_result == SPV_SUCCESS) { |
| 175 | // Allow FPRoundingMode decoration if requested. |
| 176 | if (operand.type == SPV_OPERAND_TYPE_DECORATION && |
| 177 | spv::Decoration(operand_desc->value) == |
| 178 | spv::Decoration::FPRoundingMode) { |
| 179 | if (state.features().free_fp_rounding_mode) return SPV_SUCCESS; |
| 180 | |
| 181 | // Vulkan API requires more capabilities on rounding mode. |
| 182 | if (spvIsVulkanEnv(state.context()->target_env)) { |
| 183 | enabling_capabilities.insert( |
| 184 | spv::Capability::StorageUniformBufferBlock16); |
| 185 | enabling_capabilities.insert(spv::Capability::StorageUniform16); |
| 186 | enabling_capabilities.insert(spv::Capability::StoragePushConstant16); |
| 187 | enabling_capabilities.insert(spv::Capability::StorageInputOutput16); |
| 188 | } |
| 189 | } else { |
| 190 | enabling_capabilities = state.grammar().filterCapsAgainstTargetEnv( |
| 191 | operand_desc->capabilities()); |
| 192 | } |
| 193 | |
| 194 | // When encountering an OpCapability instruction, the instruction pass |
| 195 | // registers a capability with the module *before* checking capabilities. |
| 196 | // So in the case of an OpCapability instruction, don't bother checking |
no test coverage detected