From 493723697ca705868ae90de1e4e4f8c5f73e76e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Thu, 28 Jul 2022 15:35:30 +0800 Subject: [PATCH 01/44] Adding preliminary `SpecConstant` support Used code form godot/godot as starting point. See https://github.com/KhronosGroup/SPIRV-Reflect/issues/121 Next steps: 64 bit types need 2 words as operand, `SpecConstantOp` need implementation for evaluating spec constant (spirv-cross has an implementation for uint https://github.com/KhronosGroup/SPIRV-Cross/pull/1463). Also maybe composite type evaluation support? Co-Authored-By: Juan Linietsky --- common/output_stream.cpp | 50 +++++- main.cpp | 2 +- spec_constant.patch | 302 +++++++++++++++++++++++++++++++++++ spirv_reflect.c | 328 ++++++++++++++++++++++++++++++++++++--- spirv_reflect.h | 74 ++++++++- 5 files changed, 729 insertions(+), 27 deletions(-) create mode 100644 spec_constant.patch diff --git a/common/output_stream.cpp b/common/output_stream.cpp index 0feb2c69..780bcaa5 100644 --- a/common/output_stream.cpp +++ b/common/output_stream.cpp @@ -1040,6 +1040,31 @@ void StreamWriteInterfaceVariable(std::ostream& os, const SpvReflectInterfaceVar } } +void StreamWriteSpecializationConstant(std::ostream& os, const SpvReflectSpecializationConstant& obj, const char* indent) +{ + const char* t = indent; + os << t << "spirv id : " << obj.spirv_id << "\n"; + os << t << "constant id: " << obj.constant_id << "\n"; + os << t << "name : " << (obj.name != NULL ? obj.name : "") << '\n'; + os << t << "type : "; + switch (obj.constant_type) { + case SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL: + os << "boolean\n"; + os << t << "default : " << obj.default_value.int_bool_value; + break; + case SPV_REFLECT_SPECIALIZATION_CONSTANT_INT: + os << "integer\n"; + os << t << "default : "< bindings; std::vector sets; std::vector push_constant_bocks; + std::vector specialization_constants; + + count = 0; + SpvReflectResult result = obj.EnumerateSpecializationConstants(&count, nullptr); + USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); + specialization_constants.resize(count); + result = obj.EnumerateSpecializationConstants(&count, specialization_constants.data()); + USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); + if (count > 0) { + os << "\n"; + os << "\n"; + os << "\n"; + os << t << "Sepecialization constants: " << count << "\n\n"; + for (size_t i = 0; i < specialization_constants.size(); ++i) { + auto p_var = specialization_constants[i]; + USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); + os << tt << i << ":" << "\n"; + StreamWriteSpecializationConstant(os, *p_var, ttt); + if (i < (count - 1)) { + os << "\n"; + } + } + } count = 0; - SpvReflectResult result = obj.EnumerateInputVariables(&count, nullptr); + result = obj.EnumerateInputVariables(&count, nullptr); USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); variables.resize(count); result = obj.EnumerateInputVariables(&count, variables.data()); diff --git a/main.cpp b/main.cpp index 623cbafc..6b53a14c 100644 --- a/main.cpp +++ b/main.cpp @@ -107,7 +107,7 @@ int main(int argn, char** argv) std::vector spv_data(size); spv_ifstream.read(spv_data.data(), size); - spv_reflect::ShaderModule reflection(spv_data.size(), spv_data.data()); + spv_reflect::ShaderModule reflection(spv_data.size(), spv_data.data(), SPV_REFLECT_MODULE_FLAG_EVALUATE_SPEC_CONSTANT); if (reflection.GetResult() != SPV_REFLECT_RESULT_SUCCESS) { std::cerr << "ERROR: could not process '" << input_spv_path << "' (is it a valid SPIR-V bytecode?)" << std::endl; diff --git a/spec_constant.patch b/spec_constant.patch new file mode 100644 index 00000000..c76662d8 --- /dev/null +++ b/spec_constant.patch @@ -0,0 +1,302 @@ +diff --git a/thirdparty/spirv-reflect/spirv_reflect.c b/thirdparty/spirv-reflect/spirv_reflect.c +index e9b11bf495..f181df5fa2 100644 +--- a/thirdparty/spirv-reflect/spirv_reflect.c ++++ b/thirdparty/spirv-reflect/spirv_reflect.c +@@ -125,6 +125,9 @@ typedef struct SpvReflectPrvDecorations { + SpvReflectPrvNumberDecoration location; + SpvReflectPrvNumberDecoration offset; + SpvReflectPrvNumberDecoration uav_counter_buffer; ++// -- GODOT begin -- ++ SpvReflectPrvNumberDecoration specialization_constant; ++// -- GODOT end -- + SpvReflectPrvStringDecoration semantic; + uint32_t array_stride; + uint32_t matrix_stride; +@@ -631,6 +634,9 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) + p_parser->nodes[i].decorations.offset.value = (uint32_t)INVALID_VALUE; + p_parser->nodes[i].decorations.uav_counter_buffer.value = (uint32_t)INVALID_VALUE; + p_parser->nodes[i].decorations.built_in = (SpvBuiltIn)INVALID_VALUE; ++// -- GODOT begin -- ++ p_parser->nodes[i].decorations.specialization_constant.value = (SpvBuiltIn)INVALID_VALUE; ++// -- GODOT end -- + } + // Mark source file id node + p_parser->source_file_id = (uint32_t)INVALID_VALUE; +@@ -821,10 +827,16 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) + CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id); + } + break; +- ++// -- GODOT begin -- + case SpvOpSpecConstantTrue: + case SpvOpSpecConstantFalse: +- case SpvOpSpecConstant: ++ case SpvOpSpecConstant: { ++ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id); ++ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id); ++ p_node->is_type = true; ++ } ++ break; ++// -- GODOT end -- + case SpvOpSpecConstantComposite: + case SpvOpSpecConstantOp: { + CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id); +@@ -856,7 +868,7 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) + CHECKED_READU32(p_parser, p_node->word_offset + 3, p_access_chain->base_id); + // + // SPIRV_ACCESS_CHAIN_INDEX_OFFSET (4) is the number of words up until the first index: +- // [Node, Result Type Id, Result Id, Base Id, ] ++ // [SpvReflectPrvNode, Result Type Id, Result Id, Base Id, ] + // + p_access_chain->index_count = (node_word_count - SPIRV_ACCESS_CHAIN_INDEX_OFFSET); + if (p_access_chain->index_count > 0) { +@@ -1338,6 +1350,9 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser) + skip = true; + } + break; ++// -- GODOT begin -- ++ case SpvDecorationSpecId: ++// -- GODOT end -- + case SpvDecorationRelaxedPrecision: + case SpvDecorationBlock: + case SpvDecorationBufferBlock: +@@ -1481,7 +1496,14 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser) + p_target_decorations->input_attachment_index.word_offset = word_offset; + } + break; +- ++// -- GODOT begin -- ++ case SpvDecorationSpecId: { ++ uint32_t word_offset = p_node->word_offset + member_offset+ 3; ++ CHECKED_READU32(p_parser, word_offset, p_target_decorations->specialization_constant.value); ++ p_target_decorations->specialization_constant.word_offset = word_offset; ++ } ++ break; ++// -- GODOT end -- + case SpvReflectDecorationHlslCounterBufferGOOGLE: { + uint32_t word_offset = p_node->word_offset + member_offset+ 3; + CHECKED_READU32(p_parser, word_offset, p_target_decorations->uav_counter_buffer.value); +@@ -1789,6 +1811,13 @@ static SpvReflectResult ParseType( + p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_ACCELERATION_STRUCTURE; + } + break; ++// -- GODOT begin -- ++ case SpvOpSpecConstantTrue: ++ case SpvOpSpecConstantFalse: ++ case SpvOpSpecConstant: { ++ } ++ break; ++// -- GODOT end -- + } + + if (result == SPV_REFLECT_RESULT_SUCCESS) { +@@ -3269,6 +3298,69 @@ static SpvReflectResult ParseExecutionModes( + return SPV_REFLECT_RESULT_SUCCESS; + } + ++// -- GODOT begin -- ++static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) ++{ ++ p_module->specialization_constant_count = 0; ++ p_module->specialization_constants = NULL; ++ for (size_t i = 0; i < p_parser->node_count; ++i) { ++ SpvReflectPrvNode* p_node = &(p_parser->nodes[i]); ++ if (p_node->op == SpvOpSpecConstantTrue || p_node->op == SpvOpSpecConstantFalse || p_node->op == SpvOpSpecConstant) { ++ p_module->specialization_constant_count++; ++ } ++ } ++ ++ if (p_module->specialization_constant_count == 0) { ++ return SPV_REFLECT_RESULT_SUCCESS; ++ } ++ ++ p_module->specialization_constants = (SpvReflectSpecializationConstant*)calloc(p_module->specialization_constant_count, sizeof(SpvReflectSpecializationConstant)); ++ ++ uint32_t index = 0; ++ ++ for (size_t i = 0; i < p_parser->node_count; ++i) { ++ SpvReflectPrvNode* p_node = &(p_parser->nodes[i]); ++ switch(p_node->op) { ++ default: continue; ++ case SpvOpSpecConstantTrue: { ++ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL; ++ p_module->specialization_constants[index].default_value.int_bool_value = 1; ++ } break; ++ case SpvOpSpecConstantFalse: { ++ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL; ++ p_module->specialization_constants[index].default_value.int_bool_value = 0; ++ } break; ++ case SpvOpSpecConstant: { ++ SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS; ++ uint32_t element_type_id = (uint32_t)INVALID_VALUE; ++ uint32_t default_value = 0; ++ IF_READU32(result, p_parser, p_node->word_offset + 1, element_type_id); ++ IF_READU32(result, p_parser, p_node->word_offset + 3, default_value); ++ ++ SpvReflectPrvNode* p_next_node = FindNode(p_parser, element_type_id); ++ ++ if (p_next_node->op == SpvOpTypeInt) { ++ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_INT; ++ } else if (p_next_node->op == SpvOpTypeFloat) { ++ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT; ++ } else { ++ return SPV_REFLECT_RESULT_ERROR_PARSE_FAILED; ++ } ++ ++ p_module->specialization_constants[index].default_value.int_bool_value = default_value; //bits are the same for int and float ++ } break; ++ } ++ ++ p_module->specialization_constants[index].name = p_node->name; ++ p_module->specialization_constants[index].constant_id = p_node->decorations.specialization_constant.value; ++ p_module->specialization_constants[index].spirv_id = p_node->result_id; ++ index++; ++ } ++ ++ return SPV_REFLECT_RESULT_SUCCESS; ++} ++// -- GODOT end -- ++ + static SpvReflectResult ParsePushConstantBlocks( + SpvReflectPrvParser* p_parser, + SpvReflectShaderModule* p_module) +@@ -3650,6 +3742,12 @@ static SpvReflectResult CreateShaderModule( + result = ParsePushConstantBlocks(&parser, p_module); + SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); + } ++// -- GODOT begin -- ++ if (result == SPV_REFLECT_RESULT_SUCCESS) { ++ result = ParseSpecializationConstants(&parser, p_module); ++ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); ++ } ++// -- GODOT end -- + if (result == SPV_REFLECT_RESULT_SUCCESS) { + result = ParseEntryPoints(&parser, p_module); + SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); +@@ -3807,6 +3905,9 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module) + SafeFree(p_entry->used_push_constants); + } + SafeFree(p_module->entry_points); ++// -- GODOT begin -- ++ SafeFree(p_module->specialization_constants); ++// -- GODOT end -- + + // Push constants + for (size_t i = 0; i < p_module->push_constant_block_count; ++i) { +@@ -4077,6 +4178,38 @@ SpvReflectResult spvReflectEnumerateEntryPointInterfaceVariables( + return SPV_REFLECT_RESULT_SUCCESS; + } + ++// -- GODOT begin -- ++SpvReflectResult spvReflectEnumerateSpecializationConstants( ++ const SpvReflectShaderModule* p_module, ++ uint32_t* p_count, ++ SpvReflectSpecializationConstant** pp_constants ++) ++{ ++ if (IsNull(p_module)) { ++ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; ++ } ++ if (IsNull(p_count)) { ++ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; ++ } ++ ++ if (IsNotNull(pp_constants)) { ++ if (*p_count != p_module->specialization_constant_count) { ++ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH; ++ } ++ ++ for (uint32_t index = 0; index < *p_count; ++index) { ++ SpvReflectSpecializationConstant *p_const = &p_module->specialization_constants[index]; ++ pp_constants[index] = p_const; ++ } ++ } ++ else { ++ *p_count = p_module->specialization_constant_count; ++ } ++ ++ return SPV_REFLECT_RESULT_SUCCESS; ++} ++// -- GODOT end -- ++ + SpvReflectResult spvReflectEnumerateInputVariables( + const SpvReflectShaderModule* p_module, + uint32_t* p_count, +diff --git a/thirdparty/spirv-reflect/spirv_reflect.h b/thirdparty/spirv-reflect/spirv_reflect.h +index e9e4c40755..948533d3c0 100644 +--- a/thirdparty/spirv-reflect/spirv_reflect.h ++++ b/thirdparty/spirv-reflect/spirv_reflect.h +@@ -323,6 +323,28 @@ typedef struct SpvReflectTypeDescription { + struct SpvReflectTypeDescription* members; + } SpvReflectTypeDescription; + ++// -- GODOT begin -- ++/*! @struct SpvReflectSpecializationConstant ++ ++*/ ++ ++typedef enum SpvReflectSpecializationConstantType { ++ SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL = 0, ++ SPV_REFLECT_SPECIALIZATION_CONSTANT_INT = 1, ++ SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT = 2, ++} SpvReflectSpecializationConstantType; ++ ++typedef struct SpvReflectSpecializationConstant { ++ const char* name; ++ uint32_t spirv_id; ++ uint32_t constant_id; ++ SpvReflectSpecializationConstantType constant_type; ++ union { ++ float float_value; ++ uint32_t int_bool_value; ++ } default_value; ++} SpvReflectSpecializationConstant; ++// -- GODOT end -- + + /*! @struct SpvReflectInterfaceVariable + +@@ -472,6 +494,10 @@ typedef struct SpvReflectShaderModule { + SpvReflectInterfaceVariable* interface_variables; // Uses value(s) from first entry point + uint32_t push_constant_block_count; // Uses value(s) from first entry point + SpvReflectBlockVariable* push_constant_blocks; // Uses value(s) from first entry point ++ // -- GODOT begin -- ++ uint32_t specialization_constant_count; ++ SpvReflectSpecializationConstant* specialization_constants; ++ // -- GODOT end -- + + struct Internal { + SpvReflectModuleFlags module_flags; +@@ -744,6 +770,33 @@ SpvReflectResult spvReflectEnumerateInputVariables( + SpvReflectInterfaceVariable** pp_variables + ); + ++// -- GOODT begin -- ++/*! @fn spvReflectEnumerateSpecializationConstants ++ @brief If the module contains multiple entry points, this will only get ++ the specialization constants for the first one. ++ @param p_module Pointer to an instance of SpvReflectShaderModule. ++ @param p_count If pp_constants is NULL, the module's specialization constant ++ count will be stored here. ++ If pp_variables is not NULL, *p_count must contain ++ the module's specialization constant count. ++ @param pp_variables If NULL, the module's specialization constant count will be ++ written to *p_count. ++ If non-NULL, pp_constants must point to an array with ++ *p_count entries, where pointers to the module's ++ specialization constants will be written. The caller must not ++ free the specialization constants written to this array. ++ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS. ++ Otherwise, the error code indicates the cause of the ++ failure. ++ ++*/ ++SpvReflectResult spvReflectEnumerateSpecializationConstants( ++ const SpvReflectShaderModule* p_module, ++ uint32_t* p_count, ++ SpvReflectSpecializationConstant** pp_constants ++); ++// -- GODOT end -- ++ + /*! @fn spvReflectEnumerateEntryPointInputVariables + @brief Enumerate the input variables for a given entry point. + @param entry_point The name of the entry point to get the input variables for. \ No newline at end of file diff --git a/spirv_reflect.c b/spirv_reflect.c index cdcf3ca6..a4588b36 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -126,6 +126,7 @@ typedef struct SpvReflectPrvDecorations { SpvReflectPrvNumberDecoration location; SpvReflectPrvNumberDecoration offset; SpvReflectPrvNumberDecoration uav_counter_buffer; + SpvReflectPrvNumberDecoration specialization_constant; SpvReflectPrvStringDecoration semantic; uint32_t array_stride; uint32_t matrix_stride; @@ -639,6 +640,7 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) p_parser->nodes[i].decorations.offset.value = (uint32_t)INVALID_VALUE; p_parser->nodes[i].decorations.uav_counter_buffer.value = (uint32_t)INVALID_VALUE; p_parser->nodes[i].decorations.built_in = (SpvBuiltIn)INVALID_VALUE; + p_parser->nodes[i].decorations.specialization_constant.value = (uint32_t)INVALID_VALUE; } // Mark source file id node p_parser->source_file_id = (uint32_t)INVALID_VALUE; @@ -832,7 +834,12 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) case SpvOpSpecConstantTrue: case SpvOpSpecConstantFalse: - case SpvOpSpecConstant: + case SpvOpSpecConstant: { + CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id); + CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id); + p_node->is_type = true; + } + break; case SpvOpSpecConstantComposite: case SpvOpSpecConstantOp: { CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id); @@ -1346,6 +1353,7 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser) skip = true; } break; + case SpvDecorationSpecId: case SpvDecorationRelaxedPrecision: case SpvDecorationBlock: case SpvDecorationBufferBlock: @@ -1496,6 +1504,13 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser) } break; + case SpvDecorationSpecId: { + uint32_t word_offset = p_node->word_offset + member_offset + 3; + CHECKED_READU32(p_parser, word_offset, p_target_decorations->specialization_constant.value); + p_target_decorations->specialization_constant.word_offset = word_offset; + } + break; + case SpvReflectDecorationHlslCounterBufferGOOGLE: { uint32_t word_offset = p_node->word_offset + member_offset+ 3; CHECKED_READU32(p_parser, word_offset, p_target_decorations->uav_counter_buffer.value); @@ -1803,6 +1818,12 @@ static SpvReflectResult ParseType( p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_ACCELERATION_STRUCTURE; } break; + + case SpvOpSpecConstantTrue: + case SpvOpSpecConstantFalse: + case SpvOpSpecConstant: { + } + break; } if (result == SPV_REFLECT_RESULT_SUCCESS) { @@ -3187,8 +3208,12 @@ static SpvReflectResult ParseExecutionModes( if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) { for (size_t node_idx = 0; node_idx < p_parser->node_count; ++node_idx) { SpvReflectPrvNode* p_node = &(p_parser->nodes[node_idx]); + int op_is_id = 0; if (p_node->op != SpvOpExecutionMode) { - continue; + if (p_node->op != SpvOpExecutionModeId) { + continue; + } + op_is_id = 1; } // Read entry point id @@ -3212,6 +3237,10 @@ static SpvReflectResult ParseExecutionModes( uint32_t execution_mode = (uint32_t)INVALID_VALUE; CHECKED_READU32(p_parser, p_node->word_offset + 2, execution_mode); + int is_id_mode = (execution_mode == SpvExecutionModeLocalSizeId || execution_mode == SpvExecutionModeLocalSizeHintId); + if(op_is_id && !is_id_mode) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_EXECUTION_MODE; + } // Parse execution mode switch (execution_mode) { default: { @@ -3242,13 +3271,37 @@ static SpvReflectResult ParseExecutionModes( break; case SpvExecutionModeLocalSize: { + p_entry_point->local_size.flags = 0; + CHECKED_READU32(p_parser, p_node->word_offset + 3, p_entry_point->local_size.x); + CHECKED_READU32(p_parser, p_node->word_offset + 4, p_entry_point->local_size.y); + CHECKED_READU32(p_parser, p_node->word_offset + 5, p_entry_point->local_size.z); + } + break; + + case SpvExecutionModeLocalSizeId: { + p_entry_point->local_size.flags = 1; + CHECKED_READU32(p_parser, p_node->word_offset + 3, p_entry_point->local_size.x); + CHECKED_READU32(p_parser, p_node->word_offset + 4, p_entry_point->local_size.y); + CHECKED_READU32(p_parser, p_node->word_offset + 5, p_entry_point->local_size.z); + } + break; + + case SpvExecutionModeLocalSizeHint:{ + p_entry_point->local_size.flags = 2; + CHECKED_READU32(p_parser, p_node->word_offset + 3, p_entry_point->local_size.x); + CHECKED_READU32(p_parser, p_node->word_offset + 4, p_entry_point->local_size.y); + CHECKED_READU32(p_parser, p_node->word_offset + 5, p_entry_point->local_size.z); + } + break; + + case SpvExecutionModeLocalSizeHintId: { + p_entry_point->local_size.flags = 3; CHECKED_READU32(p_parser, p_node->word_offset + 3, p_entry_point->local_size.x); CHECKED_READU32(p_parser, p_node->word_offset + 4, p_entry_point->local_size.y); CHECKED_READU32(p_parser, p_node->word_offset + 5, p_entry_point->local_size.z); } break; - case SpvExecutionModeLocalSizeHint: case SpvExecutionModeInputPoints: case SpvExecutionModeInputLines: case SpvExecutionModeInputLinesAdjacency: @@ -3271,8 +3324,6 @@ static SpvReflectResult ParseExecutionModes( case SpvExecutionModeSubgroupSize: case SpvExecutionModeSubgroupsPerWorkgroup: case SpvExecutionModeSubgroupsPerWorkgroupId: - case SpvExecutionModeLocalSizeId: - case SpvExecutionModeLocalSizeHintId: case SpvExecutionModePostDepthCoverage: case SpvExecutionModeDenormPreserve: case SpvExecutionModeDenormFlushToZero: @@ -3332,6 +3383,82 @@ static SpvReflectResult ParseExecutionModes( return SPV_REFLECT_RESULT_SUCCESS; } +static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) +{ + p_module->specialization_constant_count = 0; + p_module->specialization_constants = NULL; + for (size_t i = 0; i < p_parser->node_count; ++i) { + SpvReflectPrvNode* p_node = &(p_parser->nodes[i]); + if (p_node->op == SpvOpSpecConstantTrue || p_node->op == SpvOpSpecConstantFalse || p_node->op == SpvOpSpecConstant) { + p_module->specialization_constant_count++; + } + } + + if (p_module->specialization_constant_count == 0) { + return SPV_REFLECT_RESULT_SUCCESS; + } + + p_module->specialization_constants = (SpvReflectSpecializationConstant*)calloc(p_module->specialization_constant_count, sizeof(SpvReflectSpecializationConstant)); + + uint32_t index = 0; + + for (size_t i = 0; i < p_parser->node_count; ++i) { + SpvReflectPrvNode* p_node = &(p_parser->nodes[i]); + // Specconstants with no id means constant + switch(p_node->op) { + default: continue; + case SpvOpSpecConstantTrue: { + p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL; + p_module->specialization_constants[index].default_value.int_bool_value = 1; + p_module->specialization_constants[index].current_value.int_bool_value = 1; + } break; + case SpvOpSpecConstantFalse: { + p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL; + p_module->specialization_constants[index].default_value.int_bool_value = 0; + p_module->specialization_constants[index].current_value.int_bool_value = 0; + } break; + case SpvOpSpecConstant: { + SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS; + uint32_t element_type_id = (uint32_t)INVALID_VALUE; + uint32_t default_value = 0; + IF_READU32(result, p_parser, p_node->word_offset + 1, element_type_id); + // only support 32 bit arguments here... + IF_READU32(result, p_parser, p_node->word_offset + 3, default_value); + + SpvReflectPrvNode* p_next_node = FindNode(p_parser, element_type_id); + if(IsNull(p_next_node)){ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; + } + if (p_next_node->op == SpvOpTypeInt) { + p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_INT; + } else if (p_next_node->op == SpvOpTypeFloat) { + p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT; + } else { + return SPV_REFLECT_RESULT_ERROR_PARSE_FAILED; + } + + p_module->specialization_constants[index].default_value.int_bool_value = default_value; //bits are the same for int and float + p_module->specialization_constants[index].current_value.int_bool_value = default_value; + } break; + } + // spec constant id cannot be the same, at least for valid values. (invalid value is just constant?) + if (p_node->decorations.specialization_constant.value != (uint32_t)INVALID_VALUE) { + for (uint32_t j = 0; j < index; ++j) { + if (p_module->specialization_constants[j].constant_id == p_node->decorations.specialization_constant.value) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_DUPLICATE_SPEC_CONSTANT_NAME; + } + } + } + + p_module->specialization_constants[index].name = p_node->name; + p_module->specialization_constants[index].constant_id = p_node->decorations.specialization_constant.value; + p_module->specialization_constants[index].spirv_id = p_node->result_id; + index++; + } + + return SPV_REFLECT_RESULT_SUCCESS; +} + static SpvReflectResult ParsePushConstantBlocks( SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) @@ -3640,10 +3767,12 @@ static SpvReflectResult CreateShaderModule( memcpy(p_module->_internal->spirv_code, p_code, size); } - SpvReflectPrvParser parser = { 0 }; + // parser now works in internal field of p_module. + // SpvReflectPrvParser parser = { 0 }; + SpvReflectPrvParser* parser = (SpvReflectPrvParser*)calloc(1,sizeof(SpvReflectPrvParser)); SpvReflectResult result = CreateParser(p_module->_internal->spirv_size, p_module->_internal->spirv_code, - &parser); + parser); // Generator { @@ -3652,38 +3781,38 @@ static SpvReflectResult CreateShaderModule( } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseNodes(&parser); + result = ParseNodes(parser); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseStrings(&parser); + result = ParseStrings(parser); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseSource(&parser, p_module); + result = ParseSource(parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseFunctions(&parser); + result = ParseFunctions(parser); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseMemberCounts(&parser); + result = ParseMemberCounts(parser); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseNames(&parser); + result = ParseNames(parser); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseDecorations(&parser); + result = ParseDecorations(parser); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } // Start of reflection data parsing if (result == SPV_REFLECT_RESULT_SUCCESS) { - p_module->source_language = parser.source_language; - p_module->source_language_version = parser.source_language_version; + p_module->source_language = parser->source_language; + p_module->source_language_version = parser->source_language_version; // Zero out descriptor set data p_module->descriptor_set_count = 0; @@ -3694,11 +3823,11 @@ static SpvReflectResult CreateShaderModule( } } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseTypes(&parser, p_module); + result = ParseTypes(parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseDescriptorBindings(&parser, p_module); + result = ParseDescriptorBindings(parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { @@ -3710,15 +3839,19 @@ static SpvReflectResult CreateShaderModule( SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseDescriptorBlocks(&parser, p_module); + result = ParseDescriptorBlocks(parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParsePushConstantBlocks(&parser, p_module); + result = ParsePushConstantBlocks(parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseEntryPoints(&parser, p_module); + result = ParseSpecializationConstants(parser, p_module); + SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); + } + if (result == SPV_REFLECT_RESULT_SUCCESS) { + result = ParseEntryPoints(parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS && p_module->entry_point_count > 0) { @@ -3743,7 +3876,7 @@ static SpvReflectResult CreateShaderModule( SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseExecutionModes(&parser, p_module); + result = ParseExecutionModes(parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } @@ -3752,7 +3885,15 @@ static SpvReflectResult CreateShaderModule( spvReflectDestroyShaderModule(p_module); } - DestroyParser(&parser); + // parser is needed for evaluating specconstants + if (flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_SPEC_CONSTANT) { + p_module->_internal->parser = parser; + } + else { + DestroyParser(parser); + SafeFree(parser) + } + return result; } @@ -3875,6 +4016,7 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module) SafeFree(p_entry->execution_modes); } SafeFree(p_module->entry_points); + SafeFree(p_module->specialization_constants); // Push constants for (size_t i = 0; i < p_module->push_constant_block_count; ++i) { @@ -3896,6 +4038,11 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module) if ((p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_NO_COPY) == 0) { SafeFree(p_module->_internal->spirv_code); } + if (p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_SPEC_CONSTANT) { + DestroyParser(p_module->_internal->parser); + SafeFree(p_module->_internal->parser); + } + // Free internal SafeFree(p_module->_internal); } @@ -4175,6 +4322,36 @@ SpvReflectResult spvReflectEnumerateInputVariables( return SPV_REFLECT_RESULT_SUCCESS; } +SpvReflectResult spvReflectEnumerateSpecializationConstants( + const SpvReflectShaderModule* p_module, + uint32_t* p_count, + SpvReflectSpecializationConstant** pp_constants +) +{ + if (IsNull(p_module)) { + return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; + } + if (IsNull(p_count)) { + return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; + } + + if (IsNotNull(pp_constants)) { + if (*p_count != p_module->specialization_constant_count) { + return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH; + } + + for (uint32_t index = 0; index < *p_count; ++index) { + SpvReflectSpecializationConstant *p_const = &p_module->specialization_constants[index]; + pp_constants[index] = p_const; + } + } + else { + *p_count = p_module->specialization_constant_count; + } + + return SPV_REFLECT_RESULT_SUCCESS; +} + SpvReflectResult spvReflectEnumerateEntryPointInputVariables( const SpvReflectShaderModule* p_module, const char* entry_point, @@ -5044,3 +5221,108 @@ const char* spvReflectBlockVariableTypeName( } return p_var->type_description->type_name; } + +SpvReflectResult GetSpecContantById(SpvReflectShaderModule* p_module, uint32_t constant_id, SpvReflectSpecializationConstant** pp_constant) +{ + SpvReflectResult res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + for (uint32_t i = 0; i < p_module->specialization_constant_count; ++i) { + if (p_module->specialization_constants[i].constant_id == constant_id) { + *pp_constant = &p_module->specialization_constants[i]; + return SPV_REFLECT_RESULT_SUCCESS; + } + } + return res; +} + +// used for calculating specialization constants. +// maybe check for recursion? +SpvReflectResult EvaluateResult(SpvReflectShaderModule* p_module, uint32_t result_id, SpvReflectScalarValue* result) +{ + if (!result || !p_module) { + return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; + } + if((p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_SPEC_CONSTANT)==0){ + return SPV_REFLECT_RESULT_ERROR_PARSE_FAILED; + } + SpvReflectResult res; + SpvReflectPrvParser* p_parser = p_module->_internal->parser; + SpvReflectPrvNode* p_node = FindNode(p_parser, result_id); + if(!p_node) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; + switch (p_node->op) { + default: + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + case SpvOpConstant: + CONSTANT_RESULT: + /*switch(){ + + }*/ + // read constant value + return SPV_REFLECT_RESULT_SUCCESS; + case SpvOpSpecConstant: { + if (p_node->decorations.specialization_constant.value == (uint32_t)INVALID_VALUE) { + goto CONSTANT_RESULT; + } + SpvReflectSpecializationConstant* p_constant; + res = GetSpecContantById(p_module, p_node->decorations.specialization_constant.value, &p_constant); + if(res != SPV_REFLECT_RESULT_SUCCESS) return res; + if(p_constant->constant_type== SPV_REFLECT_SPECIALIZATION_CONSTANT_INT || + p_constant->constant_type==SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL){ + result->int_bool_value = p_constant->current_value.int_bool_value; + } + else if (p_constant->constant_type == SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT) { + result->float_value = p_constant->current_value.float_value; + } + else { + return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + } + } + return SPV_REFLECT_RESULT_SUCCESS; + case SpvOpSpecConstantComposite: + { + + } + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + case SpvOpUndef: + { + // invalid data should be handled separately? + result->int_bool_value = (uint32_t)INVALID_VALUE; + } + case SpvOpSConvert: case SpvOpUConvert: case SpvOpFConvert: + case SpvOpSNegate: case SpvOpNot: case SpvOpIAdd: case SpvOpISub: + case SpvOpIMul: case SpvOpUDiv: case SpvOpSDiv: + case SpvOpUMod: case SpvOpSRem: case SpvOpSMod: + case SpvOpShiftRightLogical: case SpvOpShiftRightArithmetic: + case SpvOpShiftLeftLogical: case SpvOpBitwiseOr: case SpvOpBitwiseXor: + case SpvOpBitwiseAnd: case SpvOpVectorShuffle: case SpvOpCompositeExtract: + case SpvOpCompositeInsert: + case SpvOpLogicalOr: case SpvOpLogicalAnd: case SpvOpLogicalNot: + case SpvOpLogicalEqual: case SpvOpLogicalNotEqual: + case SpvOpSelect: case SpvOpIEqual: case SpvOpINotEqual: + case SpvOpULessThan: case SpvOpSLessThan: + case SpvOpUGreaterThan: case SpvOpSGreaterThan: + case SpvOpULessThanEqual: case SpvOpSLessThanEqual: + case SpvOpUGreaterThanEqual: case SpvOpSGreaterThanEqual: + // add implementations here. + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + + // check shader capability... vulkan should assume this... + case SpvOpQuantizeToF16: + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + break; + + // check kernel capability... vulkan have none currently... + case SpvOpConvertFToS: case SpvOpConvertSToF: + case SpvOpConvertFToU: case SpvOpConvertUToF: + case SpvOpConvertPtrToU: case SpvOpConvertUToPtr: + case SpvOpGenericCastToPtr: case SpvOpPtrCastToGeneric: + case SpvOpBitcast: case SpvOpFNegate: + case SpvOpFAdd: case SpvOpFSub: case SpvOpFMul: case SpvOpFDiv: + case SpvOpFRem: case SpvOpFMod: + case SpvOpAccessChain: case SpvOpInBoundsAccessChain: + case SpvOpPtrAccessChain: case SpvOpInBoundsPtrAccessChain: + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + break; + } +} + + diff --git a/spirv_reflect.h b/spirv_reflect.h index 02b81613..97022fca 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -79,6 +79,8 @@ typedef enum SpvReflectResult { SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_BLOCK_MEMBER_REFERENCE, SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ENTRY_POINT, SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_EXECUTION_MODE, + SPV_REFLECT_RESULT_ERROR_SPIRV_DUPLICATE_SPEC_CONSTANT_NAME, + SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION } SpvReflectResult; /*! @enum SpvReflectModuleFlagBits @@ -92,10 +94,14 @@ SPV_REFLECT_MODULE_FLAG_NO_COPY - Disables copying of SPIR-V code This is flag is intended for cases where the memory overhead of storing the copied SPIR-V is undesirable. +SPV_REFLECT_MODULE_FLAG_EVALUATE_SPEC_CONSTANT - Keeps the parser + as long as the shader module is in lifetime. Needed for evaluating + specialization ops after specifying values. */ typedef enum SpvReflectModuleFlagBits { - SPV_REFLECT_MODULE_FLAG_NONE = 0x00000000, - SPV_REFLECT_MODULE_FLAG_NO_COPY = 0x00000001, + SPV_REFLECT_MODULE_FLAG_NONE = 0x00000000, + SPV_REFLECT_MODULE_FLAG_NO_COPY = 0x00000001, + SPV_REFLECT_MODULE_FLAG_EVALUATE_SPEC_CONSTANT = 0x00000002 } SpvReflectModuleFlagBits; typedef uint32_t SpvReflectModuleFlags; @@ -330,6 +336,29 @@ typedef struct SpvReflectTypeDescription { } SpvReflectTypeDescription; +/*! @struct SpvReflectSpecializationConstant + +*/ +typedef enum SpvReflectSpecializationConstantType { + SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL = 0, + SPV_REFLECT_SPECIALIZATION_CONSTANT_INT = 1, + SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT = 2, +} SpvReflectSpecializationConstantType; + +typedef union SpvReflectScalarValue { + float float_value; + uint32_t int_bool_value; +} SpvReflectScalarValue; + +typedef struct SpvReflectSpecializationConstant { + const char* name; + uint32_t spirv_id; + uint32_t constant_id; + SpvReflectSpecializationConstantType constant_type; + SpvReflectScalarValue default_value; + SpvReflectScalarValue current_value; +} SpvReflectSpecializationConstant; + /*! @struct SpvReflectInterfaceVariable */ @@ -451,11 +480,19 @@ typedef struct SpvReflectEntryPoint { uint32_t x; uint32_t y; uint32_t z; + int flags; // 0 if just fixed local size + // 1 bit set if is instruction id of spec constant + // 2 bit set if is hint (kernel mode not supported in vulkan, though) + // this change may break abi + // if using specialization constants, + // xyz refers to evaluated result, not just constant_id } local_size; uint32_t invocations; // valid for geometry uint32_t output_vertices; // valid for geometry, tesselation } SpvReflectEntryPoint; +typedef struct SpvReflectPrvParser SpvReflectPrvParser; + /*! @struct SpvReflectShaderModule */ @@ -484,6 +521,9 @@ typedef struct SpvReflectShaderModule { uint32_t push_constant_block_count; // Uses value(s) from first entry point SpvReflectBlockVariable* push_constant_blocks; // Uses value(s) from first entry point + uint32_t specialization_constant_count; + SpvReflectSpecializationConstant* specialization_constants; + struct Internal { SpvReflectModuleFlags module_flags; size_t spirv_size; @@ -492,6 +532,7 @@ typedef struct SpvReflectShaderModule { size_t type_description_count; SpvReflectTypeDescription* type_descriptions; + SpvReflectPrvParser* parser; } * _internal; } SpvReflectShaderModule; @@ -755,6 +796,31 @@ SpvReflectResult spvReflectEnumerateInputVariables( SpvReflectInterfaceVariable** pp_variables ); +/*! @fn spvReflectEnumerateSpecializationConstants + @brief If the module contains multiple entry points, this will only get + the specialization constants for the first one. + @param p_module Pointer to an instance of SpvReflectShaderModule. + @param p_count If pp_constants is NULL, the module's specialization constant + count will be stored here. + If pp_variables is not NULL, *p_count must contain + the module's specialization constant count. + @param pp_variables If NULL, the module's specialization constant count will be + written to *p_count. + If non-NULL, pp_constants must point to an array with + *p_count entries, where pointers to the module's + specialization constants will be written. The caller must not + free the specialization constants written to this array. + @return If successful, returns SPV_REFLECT_RESULT_SUCCESS. + Otherwise, the error code indicates the cause of the + failure. + +*/ +SpvReflectResult spvReflectEnumerateSpecializationConstants( + const SpvReflectShaderModule* p_module, + uint32_t* p_count, + SpvReflectSpecializationConstant** pp_constants +); + /*! @fn spvReflectEnumerateEntryPointInputVariables @brief Enumerate the input variables for a given entry point. @param entry_point The name of the entry point to get the input variables for. @@ -1484,6 +1550,10 @@ class ShaderModule { SpvReflectResult EnumeratePushConstants(uint32_t* p_count, SpvReflectBlockVariable** pp_blocks) const { return EnumeratePushConstantBlocks(p_count, pp_blocks); } + SpvReflectResult EnumerateSpecializationConstants(uint32_t* p_count, SpvReflectSpecializationConstant** pp_constants) const + { + return spvReflectEnumerateSpecializationConstants(&m_module, p_count, pp_constants); + } const SpvReflectDescriptorBinding* GetDescriptorBinding(uint32_t binding_number, uint32_t set_number, SpvReflectResult* p_result = nullptr) const; const SpvReflectDescriptorBinding* GetEntryPointDescriptorBinding(const char* entry_point, uint32_t binding_number, uint32_t set_number, SpvReflectResult* p_result = nullptr) const; From e1dfa44debf69a093eae91b9d3c0c135218efd4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Thu, 28 Jul 2022 18:15:16 +0800 Subject: [PATCH 02/44] Add 64 bit type support, cleanup value clutter Next step would be the constant evaluator --- common/output_stream.cpp | 53 +++++++++++--- spirv_reflect.c | 151 ++++++++++++++++++++++----------------- spirv_reflect.h | 27 ++++--- 3 files changed, 150 insertions(+), 81 deletions(-) diff --git a/common/output_stream.cpp b/common/output_stream.cpp index 780bcaa5..52675689 100644 --- a/common/output_stream.cpp +++ b/common/output_stream.cpp @@ -1047,18 +1047,53 @@ void StreamWriteSpecializationConstant(std::ostream& os, const SpvReflectSpecial os << t << "constant id: " << obj.constant_id << "\n"; os << t << "name : " << (obj.name != NULL ? obj.name : "") << '\n'; os << t << "type : "; - switch (obj.constant_type) { - case SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL: + switch (obj.default_value.type) { + case SPV_REFLECT_SCALAR_TYPE_BOOL: os << "boolean\n"; - os << t << "default : " << obj.default_value.int_bool_value; + os << t << "default : " << obj.default_value.value.int_bool_value; break; - case SPV_REFLECT_SPECIALIZATION_CONSTANT_INT: - os << "integer\n"; - os << t << "default : "<type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_ACCELERATION_STRUCTURE; } break; - - case SpvOpSpecConstantTrue: - case SpvOpSpecConstantFalse: - case SpvOpSpecConstant: { - } - break; } if (result == SPV_REFLECT_RESULT_SUCCESS) { @@ -3383,6 +3377,50 @@ static SpvReflectResult ParseExecutionModes( return SPV_REFLECT_RESULT_SUCCESS; } +SpvReflectResult GetTypeByTypeId(SpvReflectShaderModule* p_module, uint32_t type_id, SpvReflectTypeDescription** pp_type) +{ + SpvReflectResult res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; + for (uint32_t i = 0; i < p_module->_internal->type_description_count; ++i) { + if (p_module->_internal->type_descriptions[i].id == type_id) { + *pp_type = &p_module->_internal->type_descriptions[i]; + return SPV_REFLECT_RESULT_SUCCESS; + } + } + return res; +} + +static SpvReflectResult GetScalarConstant(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module, SpvReflectPrvNode* p_node, SpvReflectScalarValue* result) +{ + SpvReflectTypeDescription* type; + SpvReflectResult res = GetTypeByTypeId(p_module, p_node->result_type_id, &type); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + if(type->type_flags & SPV_REFLECT_TYPE_FLAG_INT){ + result->type = SPV_REFLECT_SCALAR_TYPE_INT; + } + else if (type->type_flags & SPV_REFLECT_TYPE_FLAG_FLOAT) { + result->type = SPV_REFLECT_SCALAR_TYPE_FLOAT; + } + else{ + result->type = SPV_REFLECT_SCALAR_TYPE_UNKNOWN; + } + result->bit_size = type->traits.numeric.scalar.width; + uint32_t low_word; + CHECKED_READU32(p_parser, p_node->word_offset + 3, low_word); + if (type->traits.numeric.scalar.width == 32) { + result->value.int_bool_value = low_word; + return SPV_REFLECT_RESULT_SUCCESS; + } + else if (type->traits.numeric.scalar.width ==64) { + uint32_t high_word; + CHECKED_READU32(p_parser, p_node->word_offset + 4, high_word); + result->value.int64_value = low_word | (((uint64_t)high_word) << 32); + return SPV_REFLECT_RESULT_SUCCESS; + } + else { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } +} + static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) { p_module->specialization_constant_count = 0; @@ -3408,37 +3446,26 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars switch(p_node->op) { default: continue; case SpvOpSpecConstantTrue: { - p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL; - p_module->specialization_constants[index].default_value.int_bool_value = 1; - p_module->specialization_constants[index].current_value.int_bool_value = 1; + p_module->specialization_constants[index].default_value.type = SPV_REFLECT_SCALAR_TYPE_BOOL; + p_module->specialization_constants[index].default_value.value.int_bool_value = 1; + p_module->specialization_constants[index].default_value.bit_size = 1; + p_module->specialization_constants[index].default_value.is_signed = 0; + p_module->specialization_constants[index].current_value = p_module->specialization_constants[index].default_value; } break; case SpvOpSpecConstantFalse: { - p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL; - p_module->specialization_constants[index].default_value.int_bool_value = 0; - p_module->specialization_constants[index].current_value.int_bool_value = 0; + p_module->specialization_constants[index].default_value.type = SPV_REFLECT_SCALAR_TYPE_BOOL; + p_module->specialization_constants[index].default_value.value.int_bool_value = 1; + p_module->specialization_constants[index].default_value.bit_size = 1; + p_module->specialization_constants[index].default_value.is_signed = 0; + p_module->specialization_constants[index].current_value = p_module->specialization_constants[index].default_value; } break; case SpvOpSpecConstant: { SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS; - uint32_t element_type_id = (uint32_t)INVALID_VALUE; - uint32_t default_value = 0; - IF_READU32(result, p_parser, p_node->word_offset + 1, element_type_id); - // only support 32 bit arguments here... - IF_READU32(result, p_parser, p_node->word_offset + 3, default_value); - - SpvReflectPrvNode* p_next_node = FindNode(p_parser, element_type_id); - if(IsNull(p_next_node)){ - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; - } - if (p_next_node->op == SpvOpTypeInt) { - p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_INT; - } else if (p_next_node->op == SpvOpTypeFloat) { - p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT; - } else { - return SPV_REFLECT_RESULT_ERROR_PARSE_FAILED; - } - - p_module->specialization_constants[index].default_value.int_bool_value = default_value; //bits are the same for int and float - p_module->specialization_constants[index].current_value.int_bool_value = default_value; + SpvReflectScalarValue default_value = { 0 }; + result = GetScalarConstant(p_parser,p_module, p_node, &default_value); + if (result != SPV_REFLECT_RESULT_SUCCESS) return result; + p_module->specialization_constants[index].default_value = default_value; + p_module->specialization_constants[index].current_value = p_module->specialization_constants[index].default_value; } break; } // spec constant id cannot be the same, at least for valid values. (invalid value is just constant?) @@ -5235,57 +5262,40 @@ SpvReflectResult GetSpecContantById(SpvReflectShaderModule* p_module, uint32_t c } // used for calculating specialization constants. -// maybe check for recursion? -SpvReflectResult EvaluateResult(SpvReflectShaderModule* p_module, uint32_t result_id, SpvReflectScalarValue* result) +SpvReflectResult EvaluateResultImpl(SpvReflectShaderModule* p_module, uint32_t result_id, SpvReflectScalarValue* result, uint32_t maxRecursion) { - if (!result || !p_module) { - return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; - } - if((p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_SPEC_CONSTANT)==0){ - return SPV_REFLECT_RESULT_ERROR_PARSE_FAILED; - } + if(!maxRecursion) return SPV_REFLECT_RESULT_ERROR_SPIRV_RECURSION; SpvReflectResult res; SpvReflectPrvParser* p_parser = p_module->_internal->parser; SpvReflectPrvNode* p_node = FindNode(p_parser, result_id); - if(!p_node) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; + if (!p_node) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; switch (p_node->op) { default: return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; case SpvOpConstant: CONSTANT_RESULT: - /*switch(){ - - }*/ - // read constant value - return SPV_REFLECT_RESULT_SUCCESS; - case SpvOpSpecConstant: { + return GetScalarConstant(p_parser, p_module, p_node, result); + + case SpvOpSpecConstant: + { if (p_node->decorations.specialization_constant.value == (uint32_t)INVALID_VALUE) { goto CONSTANT_RESULT; } SpvReflectSpecializationConstant* p_constant; res = GetSpecContantById(p_module, p_node->decorations.specialization_constant.value, &p_constant); - if(res != SPV_REFLECT_RESULT_SUCCESS) return res; - if(p_constant->constant_type== SPV_REFLECT_SPECIALIZATION_CONSTANT_INT || - p_constant->constant_type==SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL){ - result->int_bool_value = p_constant->current_value.int_bool_value; - } - else if (p_constant->constant_type == SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT) { - result->float_value = p_constant->current_value.float_value; - } - else { - return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; - } + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + *result = p_constant->current_value; } return SPV_REFLECT_RESULT_SUCCESS; case SpvOpSpecConstantComposite: { - + // only support scalar types for now... } return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; case SpvOpUndef: { // invalid data should be handled separately? - result->int_bool_value = (uint32_t)INVALID_VALUE; + result->value.int_bool_value = (uint32_t)INVALID_VALUE; } case SpvOpSConvert: case SpvOpUConvert: case SpvOpFConvert: case SpvOpSNegate: case SpvOpNot: case SpvOpIAdd: case SpvOpISub: @@ -5305,19 +5315,19 @@ SpvReflectResult EvaluateResult(SpvReflectShaderModule* p_module, uint32_t resul // add implementations here. return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; - // check shader capability... vulkan should assume this... + // check shader capability... vulkan should assume this... case SpvOpQuantizeToF16: return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; break; - // check kernel capability... vulkan have none currently... + // check kernel capability... vulkan have none currently... case SpvOpConvertFToS: case SpvOpConvertSToF: case SpvOpConvertFToU: case SpvOpConvertUToF: case SpvOpConvertPtrToU: case SpvOpConvertUToPtr: case SpvOpGenericCastToPtr: case SpvOpPtrCastToGeneric: - case SpvOpBitcast: case SpvOpFNegate: + case SpvOpBitcast: case SpvOpFNegate: case SpvOpFAdd: case SpvOpFSub: case SpvOpFMul: case SpvOpFDiv: - case SpvOpFRem: case SpvOpFMod: + case SpvOpFRem: case SpvOpFMod: case SpvOpAccessChain: case SpvOpInBoundsAccessChain: case SpvOpPtrAccessChain: case SpvOpInBoundsPtrAccessChain: return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; @@ -5326,3 +5336,16 @@ SpvReflectResult EvaluateResult(SpvReflectShaderModule* p_module, uint32_t resul } +SpvReflectResult EvaluateResult(SpvReflectShaderModule* p_module, uint32_t result_id, SpvReflectScalarValue* result) +{ + if (!result || !p_module) { + return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; + } + if((p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_SPEC_CONSTANT)==0){ + return SPV_REFLECT_RESULT_ERROR_PARSE_FAILED; + } + // compute at most 100 instruction levels, maybe defining somewhere is better. + return EvaluateResultImpl(p_module, result_id, result, 100); +} + + diff --git a/spirv_reflect.h b/spirv_reflect.h index 97022fca..fa5703e3 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -80,7 +80,8 @@ typedef enum SpvReflectResult { SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ENTRY_POINT, SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_EXECUTION_MODE, SPV_REFLECT_RESULT_ERROR_SPIRV_DUPLICATE_SPEC_CONSTANT_NAME, - SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION + SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION, + SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE } SpvReflectResult; /*! @enum SpvReflectModuleFlagBits @@ -340,21 +341,31 @@ typedef struct SpvReflectTypeDescription { */ typedef enum SpvReflectSpecializationConstantType { - SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL = 0, - SPV_REFLECT_SPECIALIZATION_CONSTANT_INT = 1, - SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT = 2, + SPV_REFLECT_SCALAR_TYPE_UNKNOWN = 0, + SPV_REFLECT_SCALAR_TYPE_BOOL = 1, + SPV_REFLECT_SCALAR_TYPE_INT = 2, + SPV_REFLECT_SCALAR_TYPE_FLOAT = 3, } SpvReflectSpecializationConstantType; -typedef union SpvReflectScalarValue { - float float_value; - uint32_t int_bool_value; +// using union may have alignment issues on certain platforms +// having type info here helps evaluating results +typedef struct SpvReflectScalarValue { + union { + float float_value; + uint32_t int_bool_value; + // c/cpp doesn't have alignment requirements + double float64_value; + uint64_t int64_value; + } value ; + SpvReflectSpecializationConstantType type; + int is_signed; + int bit_size; } SpvReflectScalarValue; typedef struct SpvReflectSpecializationConstant { const char* name; uint32_t spirv_id; uint32_t constant_id; - SpvReflectSpecializationConstantType constant_type; SpvReflectScalarValue default_value; SpvReflectScalarValue current_value; } SpvReflectSpecializationConstant; From 42372407f97486ea7756ba8b04fbf46ce3fd0806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Fri, 29 Jul 2022 15:00:23 +0800 Subject: [PATCH 03/44] Adding evaluations Keeping everything in one is difficult, also there might be better ways to do this (especially with the variant types). Modified some of the evaluation code for spec-constant array size, but not finished. --- common/output_stream.cpp | 62 ++-- spirv_reflect.c | 659 ++++++++++++++++++++++++++++++++++----- spirv_reflect.h | 49 ++- 3 files changed, 659 insertions(+), 111 deletions(-) diff --git a/common/output_stream.cpp b/common/output_stream.cpp index 52675689..f6e61400 100644 --- a/common/output_stream.cpp +++ b/common/output_stream.cpp @@ -599,7 +599,9 @@ std::string ToStringComponentType(const SpvReflectTypeDescription& type, uint32_ return ss.str(); } -void ParseBlockMembersToTextLines(const char* indent, int indent_depth, bool flatten_cbuffers, const std::string& parent_name, uint32_t member_count, const SpvReflectBlockVariable* p_members, std::vector* p_text_lines) +void ParseBlockMembersToTextLines( + const spv_reflect::ShaderModule& obj, + const char* indent, int indent_depth, bool flatten_cbuffers, const std::string& parent_name, uint32_t member_count, const SpvReflectBlockVariable* p_members, std::vector* p_text_lines) { const char* t = indent; for (uint32_t member_index = 0; member_index < member_count; ++member_index) { @@ -637,7 +639,7 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth, bool fla current_parent_name = parent_name.empty() ? name : (parent_name + "." + name); } std::vector* p_target_text_line = flatten_cbuffers ? p_text_lines : &tl.lines; - ParseBlockMembersToTextLines(t, indent_depth + 1, flatten_cbuffers, current_parent_name, member.member_count, member.members, p_target_text_line); + ParseBlockMembersToTextLines(obj, t, indent_depth + 1, flatten_cbuffers, current_parent_name, member.member_count, member.members, p_target_text_line); tl.text_line_flags = TEXT_LINE_TYPE_LINES; p_text_lines->push_back(tl); @@ -697,7 +699,13 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth, bool fla std::stringstream ss_array; for (uint32_t array_dim_index = 0; array_dim_index < member.array.dims_count; ++array_dim_index) { uint32_t dim = member.array.dims[array_dim_index]; - ss_array << "[" << dim << "]"; + if (dim == 0xFFFFFFFF) { + SpvReflectValue val{}; + SpvReflectResult res = obj.EvaluateResult(member.array.spec_constant_op_ids[array_dim_index], val); + if (res != SPV_REFLECT_RESULT_SUCCESS) throw; + dim = val.values[0].value.uint32_bool_value; + } + ss_array << "[" << dim << "]"; } tl.name += ss_array.str(); } @@ -712,7 +720,7 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth, bool fla } } -void ParseBlockVariableToTextLines(const char* indent, bool flatten_cbuffers, const SpvReflectBlockVariable& block_var, std::vector* p_text_lines) +void ParseBlockVariableToTextLines(const spv_reflect::ShaderModule& obj, const char* indent, bool flatten_cbuffers, const SpvReflectBlockVariable& block_var, std::vector* p_text_lines) { // Begin block TextLine tl = {}; @@ -725,7 +733,7 @@ void ParseBlockVariableToTextLines(const char* indent, bool flatten_cbuffers, co // Members tl = {}; - ParseBlockMembersToTextLines(indent, 2, flatten_cbuffers, "", block_var.member_count, block_var.members, &tl.lines); + ParseBlockMembersToTextLines(obj, indent, 2, flatten_cbuffers, "", block_var.member_count, block_var.members, &tl.lines); tl.text_line_flags = TEXT_LINE_TYPE_LINES; p_text_lines->push_back(tl); @@ -928,7 +936,7 @@ void StreamWriteTextLines(std::ostream& os, const char* indent, bool flatten_cbu } } -void StreamWritePushConstantsBlock(std::ostream& os, const SpvReflectBlockVariable& obj, bool flatten_cbuffers, const char* indent) +void StreamWritePushConstantsBlock(std::ostream& os, const spv_reflect::ShaderModule& shader, const SpvReflectBlockVariable& obj, bool flatten_cbuffers, const char* indent) { const char* t = indent; os << t << "spirv id : " << obj.spirv_id << "\n"; @@ -939,7 +947,7 @@ void StreamWritePushConstantsBlock(std::ostream& os, const SpvReflectBlockVariab } std::vector text_lines; - ParseBlockVariableToTextLines(" ", flatten_cbuffers, obj, &text_lines); + ParseBlockVariableToTextLines(shader, " ", flatten_cbuffers, obj, &text_lines); if (!text_lines.empty()) { os << "\n"; StreamWriteTextLines(os, t, flatten_cbuffers, text_lines); @@ -947,7 +955,7 @@ void StreamWritePushConstantsBlock(std::ostream& os, const SpvReflectBlockVariab } } -void StreamWriteDescriptorBinding(std::ostream& os, const SpvReflectDescriptorBinding& obj, bool write_set, bool flatten_cbuffers, const char* indent) +void StreamWriteDescriptorBinding(std::ostream& os, const spv_reflect::ShaderModule& shader, const SpvReflectDescriptorBinding& obj, bool write_set, bool flatten_cbuffers, const char* indent) { const char* t = indent; os << t << "spirv id : " << obj.spirv_id << "\n"; @@ -992,7 +1000,7 @@ void StreamWriteDescriptorBinding(std::ostream& os, const SpvReflectDescriptorBi if (obj.descriptor_type == SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER || obj.descriptor_type == SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER) { std::vector text_lines; - ParseBlockVariableToTextLines(" ", flatten_cbuffers, obj.block, &text_lines); + ParseBlockVariableToTextLines(shader, " ", flatten_cbuffers, obj.block, &text_lines); if (!text_lines.empty()) { os << "\n"; StreamWriteTextLines(os, t, flatten_cbuffers, text_lines); @@ -1047,35 +1055,35 @@ void StreamWriteSpecializationConstant(std::ostream& os, const SpvReflectSpecial os << t << "constant id: " << obj.constant_id << "\n"; os << t << "name : " << (obj.name != NULL ? obj.name : "") << '\n'; os << t << "type : "; - switch (obj.default_value.type) { + switch (obj.general_type) { case SPV_REFLECT_SCALAR_TYPE_BOOL: os << "boolean\n"; - os << t << "default : " << obj.default_value.value.int_bool_value; + os << t << "default : " << obj.default_value.value.uint32_bool_value; break; case SPV_REFLECT_SCALAR_TYPE_INT: - if (obj.default_value.is_signed) { + if (obj.type->traits.numeric.scalar.signedness) { os << "signed "; } else { os << "unsigned "; } - os<traits.numeric.scalar.width <<" bit integer\n"; os << t << "default : "; // let's assume only 32 bit and 64 bit types (no 8 and 16 bit types here) - if (obj.default_value.bit_size == 32) { - if (obj.default_value.is_signed) { - os << (int32_t)obj.default_value.value.int_bool_value; + if (obj.type->traits.numeric.scalar.width == 32) { + if (obj.type->traits.numeric.scalar.signedness) { + os << obj.default_value.value.sint32_value; } else { - os << (uint32_t)obj.default_value.value.int_bool_value; + os << obj.default_value.value.uint32_bool_value; } } - else if(obj.default_value.bit_size == 64){ - if (obj.default_value.is_signed) { - os << (int64_t)obj.default_value.value.int64_value; + else if(obj.type->traits.numeric.scalar.width == 64){ + if (obj.type->traits.numeric.scalar.signedness) { + os << obj.default_value.value.sint64_value; } else { - os << (uint32_t)obj.default_value.value.int64_value; + os << obj.default_value.value.uint64_value; } } else { @@ -1083,12 +1091,12 @@ void StreamWriteSpecializationConstant(std::ostream& os, const SpvReflectSpecial } break; case SPV_REFLECT_SCALAR_TYPE_FLOAT: - os << obj.default_value.bit_size << " bit floating point\n"; + os << obj.type->traits.numeric.scalar.width << " bit floating point\n"; os << t << "default : "; - if (obj.default_value.bit_size == 32) { - os << obj.default_value.value.float_value; + if (obj.type->traits.numeric.scalar.width == 32) { + os << obj.default_value.value.float32_value; } - else if (obj.default_value.bit_size == 64) { + else if (obj.type->traits.numeric.scalar.width == 64) { os << obj.default_value.value.float64_value; } else { @@ -1230,7 +1238,7 @@ void WriteReflection(const spv_reflect::ShaderModule& obj, bool flatten_cbuffers for (size_t i = 0; i < push_constant_bocks.size(); ++i) { auto p_block = push_constant_bocks[i]; os << tt << i << ":" << "\n"; - StreamWritePushConstantsBlock(os, *p_block, flatten_cbuffers, ttt); + StreamWritePushConstantsBlock(os, obj, *p_block, flatten_cbuffers, ttt); } } @@ -1257,7 +1265,7 @@ void WriteReflection(const spv_reflect::ShaderModule& obj, bool flatten_cbuffers auto p_binding = bindings[i]; USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); os << tt << "Binding" << " " << p_binding->set << "." << p_binding->binding << "" << "\n"; - StreamWriteDescriptorBinding(os, *p_binding, true, flatten_cbuffers, ttt); + StreamWriteDescriptorBinding(os, obj, *p_binding, true, flatten_cbuffers, ttt); if (i < (count - 1)) { os << "\n\n"; } diff --git a/spirv_reflect.c b/spirv_reflect.c index ebe78a42..0b6bc443 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -3377,7 +3377,7 @@ static SpvReflectResult ParseExecutionModes( return SPV_REFLECT_RESULT_SUCCESS; } -SpvReflectResult GetTypeByTypeId(SpvReflectShaderModule* p_module, uint32_t type_id, SpvReflectTypeDescription** pp_type) +SpvReflectResult GetTypeByTypeId(const SpvReflectShaderModule* p_module, uint32_t type_id, SpvReflectTypeDescription** pp_type) { SpvReflectResult res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; for (uint32_t i = 0; i < p_module->_internal->type_description_count; ++i) { @@ -3389,36 +3389,85 @@ SpvReflectResult GetTypeByTypeId(SpvReflectShaderModule* p_module, uint32_t type return res; } -static SpvReflectResult GetScalarConstant(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module, SpvReflectPrvNode* p_node, SpvReflectScalarValue* result) +#define SCALAR_TYPE_FLAGS (SPV_REFLECT_TYPE_FLAG_BOOL | SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_FLOAT) +#define SCALAR_DISALLOWED_FLAGS (~0 ^ SCALAR_TYPE_FLAGS) +#define VECTOR_TYPE_FLAGS (SCALAR_TYPE_FLAGS | SPV_REFLECT_TYPE_FLAG_VECTOR) +#define VECTOR_DISALLOWED_FLAGS (~0 ^ VECTOR_TYPE_FLAGS) + +static SpvReflectScalarType ScalarGeneralTypeFromType(SpvReflectTypeDescription* type) { - SpvReflectTypeDescription* type; - SpvReflectResult res = GetTypeByTypeId(p_module, p_node->result_type_id, &type); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - if(type->type_flags & SPV_REFLECT_TYPE_FLAG_INT){ - result->type = SPV_REFLECT_SCALAR_TYPE_INT; + if ((type->type_flags & SCALAR_TYPE_FLAGS) == SPV_REFLECT_TYPE_FLAG_BOOL) { + return SPV_REFLECT_SCALAR_TYPE_BOOL; + } + else if ((type->type_flags & SCALAR_TYPE_FLAGS) == SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_SCALAR_TYPE_INT; } - else if (type->type_flags & SPV_REFLECT_TYPE_FLAG_FLOAT) { - result->type = SPV_REFLECT_SCALAR_TYPE_FLOAT; + else if ((type->type_flags & SCALAR_TYPE_FLAGS) == SPV_REFLECT_TYPE_FLAG_FLOAT) { + return SPV_REFLECT_SCALAR_TYPE_FLOAT; } - else{ - result->type = SPV_REFLECT_SCALAR_TYPE_UNKNOWN; + else { + return SPV_REFLECT_SCALAR_TYPE_UNKNOWN; } - result->bit_size = type->traits.numeric.scalar.width; +} + +static SpvReflectResult GetScalarConstant(const SpvReflectShaderModule* p_module, SpvReflectPrvNode* p_node, + SpvReflectScalarValue* result, SpvReflectScalarType* general_type, SpvReflectTypeDescription** type) +{ + SpvReflectPrvParser* p_parser = p_module->_internal->parser; + + SpvReflectScalarType g_type; + SpvReflectTypeDescription* d_type; + SpvReflectResult res = GetTypeByTypeId(p_module, p_node->result_type_id, &d_type); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + + if(d_type->type_flags & SCALAR_DISALLOWED_FLAGS) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + g_type = ScalarGeneralTypeFromType(d_type); uint32_t low_word; CHECKED_READU32(p_parser, p_node->word_offset + 3, low_word); - if (type->traits.numeric.scalar.width == 32) { - result->value.int_bool_value = low_word; - return SPV_REFLECT_RESULT_SUCCESS; + // There is no alignment requirements in c/cpp for unions + if (d_type->traits.numeric.scalar.width == 32) { + if (g_type == SPV_REFLECT_SCALAR_TYPE_FLOAT) { + memcpy(&result->value.float32_value, &low_word, 4); + } + else if (g_type == SPV_REFLECT_SCALAR_TYPE_INT) { + if (d_type->traits.numeric.scalar.signedness) { + memcpy(&result->value.sint32_value, &low_word, 4); + } + else { + memcpy(&result->value.uint32_bool_value, &low_word, 4); + } + } + else { + //memcpy(&result->value.uint32_bool_value, &low_word, 4); + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } } - else if (type->traits.numeric.scalar.width ==64) { + else if (d_type->traits.numeric.scalar.width ==64) { uint32_t high_word; CHECKED_READU32(p_parser, p_node->word_offset + 4, high_word); - result->value.int64_value = low_word | (((uint64_t)high_word) << 32); - return SPV_REFLECT_RESULT_SUCCESS; + uint64_t combined = low_word | (((uint64_t)high_word) << 32); + if (g_type == SPV_REFLECT_SCALAR_TYPE_FLOAT) { + memcpy(&result->value.float64_value, &combined, 8); + } + else if (g_type == SPV_REFLECT_SCALAR_TYPE_INT) { + if (d_type->traits.numeric.scalar.signedness) { + memcpy(&result->value.sint64_value, &combined, 8); + } + else { + memcpy(&result->value.uint64_value, &combined, 8); + } + } + else { + //memcpy(&result->value.uint32_bool_value, &combined, 8); + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } } else { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } + *general_type = g_type; + *type = d_type; + return SPV_REFLECT_RESULT_SUCCESS; } static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) @@ -3446,23 +3495,19 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars switch(p_node->op) { default: continue; case SpvOpSpecConstantTrue: { - p_module->specialization_constants[index].default_value.type = SPV_REFLECT_SCALAR_TYPE_BOOL; - p_module->specialization_constants[index].default_value.value.int_bool_value = 1; - p_module->specialization_constants[index].default_value.bit_size = 1; - p_module->specialization_constants[index].default_value.is_signed = 0; + p_module->specialization_constants[index].general_type = SPV_REFLECT_SCALAR_TYPE_BOOL; + p_module->specialization_constants[index].default_value.value.uint32_bool_value = 1; p_module->specialization_constants[index].current_value = p_module->specialization_constants[index].default_value; } break; case SpvOpSpecConstantFalse: { - p_module->specialization_constants[index].default_value.type = SPV_REFLECT_SCALAR_TYPE_BOOL; - p_module->specialization_constants[index].default_value.value.int_bool_value = 1; - p_module->specialization_constants[index].default_value.bit_size = 1; - p_module->specialization_constants[index].default_value.is_signed = 0; + p_module->specialization_constants[index].general_type = SPV_REFLECT_SCALAR_TYPE_BOOL; + p_module->specialization_constants[index].default_value.value.uint32_bool_value = 0; p_module->specialization_constants[index].current_value = p_module->specialization_constants[index].default_value; } break; case SpvOpSpecConstant: { SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS; SpvReflectScalarValue default_value = { 0 }; - result = GetScalarConstant(p_parser,p_module, p_node, &default_value); + result = GetScalarConstant(p_module, p_node, &default_value, &p_module->specialization_constants[index].general_type, &p_module->specialization_constants[index].type); if (result != SPV_REFLECT_RESULT_SUCCESS) return result; p_module->specialization_constants[index].default_value = default_value; p_module->specialization_constants[index].current_value = p_module->specialization_constants[index].default_value; @@ -3800,6 +3845,8 @@ static SpvReflectResult CreateShaderModule( SpvReflectResult result = CreateParser(p_module->_internal->spirv_size, p_module->_internal->spirv_code, parser); + // used by spec constant parsing GetScalarConstant + p_module->_internal->parser = parser; // Generator { @@ -5249,7 +5296,7 @@ const char* spvReflectBlockVariableTypeName( return p_var->type_description->type_name; } -SpvReflectResult GetSpecContantById(SpvReflectShaderModule* p_module, uint32_t constant_id, SpvReflectSpecializationConstant** pp_constant) +SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint32_t constant_id, SpvReflectSpecializationConstant** pp_constant) { SpvReflectResult res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; for (uint32_t i = 0; i < p_module->specialization_constant_count; ++i) { @@ -5262,20 +5309,32 @@ SpvReflectResult GetSpecContantById(SpvReflectShaderModule* p_module, uint32_t c } // used for calculating specialization constants. -SpvReflectResult EvaluateResultImpl(SpvReflectShaderModule* p_module, uint32_t result_id, SpvReflectScalarValue* result, uint32_t maxRecursion) +SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint32_t result_id, SpvReflectValue* result, uint32_t maxRecursion) { if(!maxRecursion) return SPV_REFLECT_RESULT_ERROR_SPIRV_RECURSION; - SpvReflectResult res; + SpvReflectResult res = SPV_REFLECT_RESULT_SUCCESS; SpvReflectPrvParser* p_parser = p_module->_internal->parser; SpvReflectPrvNode* p_node = FindNode(p_parser, result_id); if (!p_node) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; switch (p_node->op) { default: return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + case SpvOpConstantTrue: + { + result->general_type = SPV_REFLECT_SCALAR_TYPE_BOOL; + result->values[0].value.uint32_bool_value = 1; + } + return SPV_REFLECT_RESULT_SUCCESS; + case SpvOpConstantFalse: + { + result->general_type = SPV_REFLECT_SCALAR_TYPE_BOOL; + result->values[0].value.uint32_bool_value = 0; + } + return SPV_REFLECT_RESULT_SUCCESS; case SpvOpConstant: CONSTANT_RESULT: - return GetScalarConstant(p_parser, p_module, p_node, result); - + return GetScalarConstant(p_module, p_node, &result->values[0], &result->general_type, &result->type); + case SpvOpSpecConstantTrue: case SpvOpSpecConstantFalse: case SpvOpSpecConstant: { if (p_node->decorations.specialization_constant.value == (uint32_t)INVALID_VALUE) { @@ -5284,7 +5343,9 @@ SpvReflectResult EvaluateResultImpl(SpvReflectShaderModule* p_module, uint32_t r SpvReflectSpecializationConstant* p_constant; res = GetSpecContantById(p_module, p_node->decorations.specialization_constant.value, &p_constant); if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - *result = p_constant->current_value; + result->general_type = p_constant->general_type; + result->type = p_constant->type; + result->values[0] = p_constant->current_value; } return SPV_REFLECT_RESULT_SUCCESS; case SpvOpSpecConstantComposite: @@ -5292,51 +5353,507 @@ SpvReflectResult EvaluateResultImpl(SpvReflectShaderModule* p_module, uint32_t r // only support scalar types for now... } return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; - case SpvOpUndef: + case SpvOpSpecConstantOp: { - // invalid data should be handled separately? - result->value.int_bool_value = (uint32_t)INVALID_VALUE; - } - case SpvOpSConvert: case SpvOpUConvert: case SpvOpFConvert: - case SpvOpSNegate: case SpvOpNot: case SpvOpIAdd: case SpvOpISub: - case SpvOpIMul: case SpvOpUDiv: case SpvOpSDiv: - case SpvOpUMod: case SpvOpSRem: case SpvOpSMod: - case SpvOpShiftRightLogical: case SpvOpShiftRightArithmetic: - case SpvOpShiftLeftLogical: case SpvOpBitwiseOr: case SpvOpBitwiseXor: - case SpvOpBitwiseAnd: case SpvOpVectorShuffle: case SpvOpCompositeExtract: - case SpvOpCompositeInsert: - case SpvOpLogicalOr: case SpvOpLogicalAnd: case SpvOpLogicalNot: - case SpvOpLogicalEqual: case SpvOpLogicalNotEqual: - case SpvOpSelect: case SpvOpIEqual: case SpvOpINotEqual: - case SpvOpULessThan: case SpvOpSLessThan: - case SpvOpUGreaterThan: case SpvOpSGreaterThan: - case SpvOpULessThanEqual: case SpvOpSLessThanEqual: - case SpvOpUGreaterThanEqual: case SpvOpSGreaterThanEqual: - // add implementations here. - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + // operation has result type id, thus must be typed + res = GetTypeByTypeId(p_module, p_node->result_type_id, &result->type); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - // check shader capability... vulkan should assume this... - case SpvOpQuantizeToF16: - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; - break; + // no support for vectors yet... + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + } - // check kernel capability... vulkan have none currently... - case SpvOpConvertFToS: case SpvOpConvertSToF: - case SpvOpConvertFToU: case SpvOpConvertUToF: - case SpvOpConvertPtrToU: case SpvOpConvertUToPtr: - case SpvOpGenericCastToPtr: case SpvOpPtrCastToGeneric: - case SpvOpBitcast: case SpvOpFNegate: - case SpvOpFAdd: case SpvOpFSub: case SpvOpFMul: case SpvOpFDiv: - case SpvOpFRem: case SpvOpFMod: - case SpvOpAccessChain: case SpvOpInBoundsAccessChain: - case SpvOpPtrAccessChain: case SpvOpInBoundsPtrAccessChain: - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; - break; + // only vector and scalar types of int/bool/float types allowed + if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + result->general_type = ScalarGeneralTypeFromType(result->type); + + // evaluate op + uint32_t spec_op; + CHECKED_READU32(p_parser, p_node->word_offset + 3, spec_op); + spec_op &= 0xFFFF; + switch (spec_op) { + default: + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + case SpvOpUndef: + { + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + for (uint32_t i = 0; i < result->type->traits.numeric.vector.component_count; ++i) { + result->values[i].undefined_value = 1; + } + } + else { + result->values[0].undefined_value = 1; + } + } + return SPV_REFLECT_RESULT_SUCCESS; + case SpvOpSConvert: + // maybe there's a more clever way? + { + // convert of signed integer to any integer of different width. + // result is scalar or vector integer type. + // vectors should be of same length + + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + // check type here, remember undefined value and booleans with type == null + if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + // operand must be signed + if (!operand1.type->traits.numeric.scalar.signedness) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + // vector size must match + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + vec_size = operand1.type->traits.numeric.vector.component_count; + } + + // now do the job + for (uint32_t i = 0; i < vec_size; ++i) { + result->values[i].undefined_value = operand1.values->undefined_value; + switch (operand1.type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + // convert int32 to generic integer type + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + if (result->type->traits.numeric.scalar.signedness) { + result->values[i].value.sint32_value = operand1.values[i].value.sint32_value; + } + else { + result->values[i].value.uint32_bool_value = (uint32_t)operand1.values[i].value.sint32_value; + } + break; + case 64: + if (result->type->traits.numeric.scalar.signedness) { + result->values[i].value.sint64_value = (int64_t)operand1.values[i].value.sint32_value; + } + else { + result->values[i].value.uint64_value = (uint64_t)operand1.values[i].value.sint32_value; + } + break; + } + break; + case 64: + // convert int64 to generic integer type + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + if (result->type->traits.numeric.scalar.signedness) { + result->values[i].value.sint32_value = (int32_t)operand1.values[i].value.sint64_value; + } + else { + result->values[i].value.uint32_bool_value = (uint32_t)operand1.values[i].value.sint64_value; + } + break; + case 64: + if (result->type->traits.numeric.scalar.signedness) { + result->values[i].value.sint64_value = operand1.values[i].value.sint64_value; + } + else { + result->values[i].value.uint64_value = (uint64_t)operand1.values[i].value.sint64_value; + } + break; + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; + } + case SpvOpUConvert: + { + // convert of unsigned integer to any integer of different width. + // result is scalar or vector integer type. + // vectors should be of same length + + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + // check type here, remember undefined value and booleans with type == null + if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + // operand must not be signed + if (operand1.type->traits.numeric.scalar.signedness) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + // vector size must match + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + vec_size = operand1.type->traits.numeric.vector.component_count; + } + + // now do the job + for (uint32_t i = 0; i < vec_size; ++i) { + result->values[i].undefined_value = operand1.values->undefined_value; + switch (operand1.type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + // convert int32 to generic integer type + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + if (result->type->traits.numeric.scalar.signedness) { + result->values[i].value.sint32_value = operand1.values[i].value.uint32_bool_value; + } + else { + result->values[i].value.uint32_bool_value = (uint32_t)operand1.values[i].value.uint32_bool_value; + } + break; + case 64: + if (result->type->traits.numeric.scalar.signedness) { + result->values[i].value.sint64_value = (int64_t)operand1.values[i].value.uint32_bool_value; + } + else { + result->values[i].value.uint64_value = (uint64_t)operand1.values[i].value.uint32_bool_value; + } + break; + } + break; + case 64: + // convert int64 to generic integer type + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + if (result->type->traits.numeric.scalar.signedness) { + result->values[i].value.sint32_value = (int32_t)operand1.values[i].value.uint64_value; + } + else { + result->values[i].value.uint32_bool_value = (uint32_t)operand1.values[i].value.uint64_value; + } + break; + case 64: + if (result->type->traits.numeric.scalar.signedness) { + result->values[i].value.sint64_value = operand1.values[i].value.uint64_value; + } + else { + result->values[i].value.uint64_value = (uint64_t)operand1.values[i].value.uint64_value; + } + break; + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; + } + case SpvOpFConvert: + { + // convert of floating point integer to any integer of different width. + // just 32 and 64 bit for now... + + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_FLOAT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + // check type here, remember undefined value and booleans with type == null + if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_FLOAT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + // vector size must match + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + vec_size = operand1.type->traits.numeric.vector.component_count; + } + + // now do the job + for (uint32_t i = 0; i < vec_size; ++i) { + result->values[i].undefined_value = operand1.values->undefined_value; + switch (operand1.type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + // convert int32 to generic integer type + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + result->values[i].value.float32_value = operand1.values[i].value.float32_value; + break; + case 64: + result->values[i].value.float64_value = (double)operand1.values[i].value.float32_value; + break; + } + break; + case 64: + // convert int64 to generic integer type + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + result->values[i].value.float32_value = (float)operand1.values[i].value.float64_value; + break; + case 64: + result->values[i].value.float64_value = operand1.values[i].value.float64_value; + break; + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; + } + case SpvOpSNegate: + { + // compute minus sign of op1, not in current spec of what happens if op1 is uint + + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + // check type here, remember undefined value and booleans with type == null + if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + // operand must be signed + if (!operand1.type->traits.numeric.scalar.signedness) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + // vector size must match + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + vec_size = operand1.type->traits.numeric.vector.component_count; + } + + // now do the job + for (uint32_t i = 0; i < vec_size; ++i) { + result->values[i].undefined_value = operand1.values->undefined_value; + switch (operand1.type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + // convert int32 to generic integer type + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + if (result->type->traits.numeric.scalar.signedness) { + result->values[i].value.sint32_value = -operand1.values[i].value.sint32_value; + } + else { + result->values[i].value.uint32_bool_value = (uint32_t)(-operand1.values[i].value.sint32_value); + } + break; + case 64: + if (result->type->traits.numeric.scalar.signedness) { + result->values[i].value.sint64_value = -(int64_t)operand1.values[i].value.sint32_value; + } + else { + result->values[i].value.uint64_value = (uint64_t)(-operand1.values[i].value.sint32_value); + } + break; + } + break; + case 64: + // convert int64 to generic integer type + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + if (result->type->traits.numeric.scalar.signedness) { + result->values[i].value.sint32_value = (int32_t)(-operand1.values[i].value.sint64_value); + } + else { + result->values[i].value.uint32_bool_value = (uint32_t)(-operand1.values[i].value.sint64_value); + } + break; + case 64: + if (result->type->traits.numeric.scalar.signedness) { + result->values[i].value.sint64_value = -operand1.values[i].value.sint64_value; + } + else { + result->values[i].value.uint64_value = (uint64_t)(-operand1.values[i].value.sint64_value); + } + break; + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; + case SpvOpNot: + { + // bitwise not of every component in op1, store into same width result. + + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + // check type here, remember undefined value and booleans with type == null + if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + // width must match + if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + // vector size must match + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + vec_size = operand1.type->traits.numeric.vector.component_count; + } + + // now do the job + for (uint32_t i = 0; i < vec_size; ++i) { + result->values[i].undefined_value = operand1.values->undefined_value; + switch (operand1.type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + // load data into uint32_t + uint32_t data; + if (operand1.type->traits.numeric.scalar.signedness) { + memcpy(&data, &operand1.values[i].value.sint32_value, 4); + } + else{ + memcpy(&data, &operand1.values[i].value.uint32_bool_value, 4); + } + data ^= 0xffffffff; + // write to correct offset + if (result->type->traits.numeric.scalar.signedness) { + memcpy(&result->values[i].value.sint32_value, &data, 4); + } + else { + memcpy(&result->values[i].value.uint32_bool_value, &data, 4); + } + break; + case 64: + // load data into uint64_t + uint64_t data; + if (operand1.type->traits.numeric.scalar.signedness) { + memcpy(&data, &operand1.values[i].value.sint64_value, 8); + } + else { + memcpy(&data, &operand1.values[i].value.uint64_value, 8); + } + data ^= 0xffffffffffffffff; + // write to correct offset + if (result->type->traits.numeric.scalar.signedness) { + memcpy(&result->values[i].value.sint64_value, &data, 8); + } + else { + memcpy(&result->values[i].value.uint64_value, &data, 8); + } + break; + } + } + return SPV_REFLECT_RESULT_SUCCESS; + + case SpvOpIAdd: + // integer add. + + case SpvOpISub: + // integer subtract + + case SpvOpIMul: + // integer multiply + + case SpvOpUDiv: + // unsigned divide + + case SpvOpSDiv: + // signed divide + + case SpvOpUMod: case SpvOpSRem: case SpvOpSMod: + case SpvOpShiftRightLogical: case SpvOpShiftRightArithmetic: + case SpvOpShiftLeftLogical: case SpvOpBitwiseOr: case SpvOpBitwiseXor: + case SpvOpBitwiseAnd: case SpvOpVectorShuffle: case SpvOpCompositeExtract: + case SpvOpCompositeInsert: + case SpvOpLogicalOr: case SpvOpLogicalAnd: case SpvOpLogicalNot: + case SpvOpLogicalEqual: case SpvOpLogicalNotEqual: + case SpvOpSelect: case SpvOpIEqual: case SpvOpINotEqual: + case SpvOpULessThan: case SpvOpSLessThan: + case SpvOpUGreaterThan: case SpvOpSGreaterThan: + case SpvOpULessThanEqual: case SpvOpSLessThanEqual: + case SpvOpUGreaterThanEqual: case SpvOpSGreaterThanEqual: + // add implementations here. + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + + // check shader capability... vulkan should assume this... + case SpvOpQuantizeToF16: + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + break; + + // check kernel capability... vulkan have none currently... + case SpvOpConvertFToS: case SpvOpConvertSToF: + case SpvOpConvertFToU: case SpvOpConvertUToF: + case SpvOpConvertPtrToU: case SpvOpConvertUToPtr: + case SpvOpGenericCastToPtr: case SpvOpPtrCastToGeneric: + case SpvOpBitcast: case SpvOpFNegate: + case SpvOpFAdd: case SpvOpFSub: case SpvOpFMul: case SpvOpFDiv: + case SpvOpFRem: case SpvOpFMod: + case SpvOpAccessChain: case SpvOpInBoundsAccessChain: + case SpvOpPtrAccessChain: case SpvOpInBoundsPtrAccessChain: + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + break; + + } + } } } -SpvReflectResult EvaluateResult(SpvReflectShaderModule* p_module, uint32_t result_id, SpvReflectScalarValue* result) +SpvReflectResult EvaluateResult(const SpvReflectShaderModule* p_module, uint32_t result_id, SpvReflectValue* result) { if (!result || !p_module) { return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; diff --git a/spirv_reflect.h b/spirv_reflect.h index fa5703e3..f5dd32cc 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -264,6 +264,7 @@ typedef enum SpvReflectGenerator { } SpvReflectGenerator; enum { + SPV_REFLECT_MAX_VECTOR_DIMS = 4, SPV_REFLECT_MAX_ARRAY_DIMS = 32, SPV_REFLECT_MAX_DESCRIPTOR_SETS = 64, }; @@ -340,34 +341,49 @@ typedef struct SpvReflectTypeDescription { /*! @struct SpvReflectSpecializationConstant */ -typedef enum SpvReflectSpecializationConstantType { +typedef enum SpvReflectScalarType { SPV_REFLECT_SCALAR_TYPE_UNKNOWN = 0, SPV_REFLECT_SCALAR_TYPE_BOOL = 1, SPV_REFLECT_SCALAR_TYPE_INT = 2, SPV_REFLECT_SCALAR_TYPE_FLOAT = 3, -} SpvReflectSpecializationConstantType; +} SpvReflectScalarType; -// using union may have alignment issues on certain platforms -// having type info here helps evaluating results +// 16 bit floating point can be common. Just a bitwise representation here... +typedef uint16_t spv_reflect_float16_t; typedef struct SpvReflectScalarValue { + // strongly typed for evaluation purpose union { - float float_value; - uint32_t int_bool_value; - // c/cpp doesn't have alignment requirements + spv_reflect_float16_t float16_value; + float float32_value; double float64_value; - uint64_t int64_value; - } value ; - SpvReflectSpecializationConstantType type; - int is_signed; - int bit_size; + uint32_t uint32_bool_value; + uint64_t uint64_value; + int32_t sint32_value; + int64_t sint64_value; + } value; + // for use with OpUndef + int undefined_value; } SpvReflectScalarValue; +// only scalar, vector types can evaluate values for now... +typedef struct SpvReflectValue { + SpvReflectScalarType general_type; + // may be null if boolean, coming from OpSpecConstantTrue/OpSpecConstantFalse + SpvReflectTypeDescription* type; + SpvReflectScalarValue values[SPV_REFLECT_MAX_VECTOR_DIMS]; +} SpvReflectValue; + typedef struct SpvReflectSpecializationConstant { - const char* name; uint32_t spirv_id; uint32_t constant_id; + SpvReflectScalarType general_type; + + SpvReflectTypeDescription* type; + const char* name; + SpvReflectScalarValue default_value; SpvReflectScalarValue current_value; + } SpvReflectSpecializationConstant; /*! @struct SpvReflectInterfaceVariable @@ -1499,6 +1515,8 @@ const char* spvReflectBlockVariableTypeName( const SpvReflectBlockVariable* p_var ); +SpvReflectResult EvaluateResult(const SpvReflectShaderModule* p_module, uint32_t result_id, SpvReflectValue* result); + #if defined(__cplusplus) }; #endif @@ -1605,6 +1623,11 @@ class ShaderModule { SpvReflectResult ChangeInputVariableLocation(const SpvReflectInterfaceVariable* p_input_variable, uint32_t new_location); SpvReflectResult ChangeOutputVariableLocation(const SpvReflectInterfaceVariable* p_output_variable, uint32_t new_location); + SpvReflectResult EvaluateResult(uint32_t result_id, SpvReflectValue& result) const + { + return ::EvaluateResult(&m_module, result_id, &result); + } + private: // Make noncopyable ShaderModule(const ShaderModule&); From 79fbd2ed992e4c0525d03f92670c6245dd86c8ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Fri, 29 Jul 2022 21:54:41 +0800 Subject: [PATCH 04/44] Adding arithmetic operations `memcpy` is required for strict aliasing rule. union member offset in c++ requires c++14 to guarantee (though c style code should always work on reasonable compilers.) --- spirv_reflect.c | 492 ++++++++++++++++++++++++++++++++++++++++-------- spirv_reflect.h | 3 + 2 files changed, 420 insertions(+), 75 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index 0b6bc443..b950a32a 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -3426,41 +3426,13 @@ static SpvReflectResult GetScalarConstant(const SpvReflectShaderModule* p_module CHECKED_READU32(p_parser, p_node->word_offset + 3, low_word); // There is no alignment requirements in c/cpp for unions if (d_type->traits.numeric.scalar.width == 32) { - if (g_type == SPV_REFLECT_SCALAR_TYPE_FLOAT) { - memcpy(&result->value.float32_value, &low_word, 4); - } - else if (g_type == SPV_REFLECT_SCALAR_TYPE_INT) { - if (d_type->traits.numeric.scalar.signedness) { - memcpy(&result->value.sint32_value, &low_word, 4); - } - else { - memcpy(&result->value.uint32_bool_value, &low_word, 4); - } - } - else { - //memcpy(&result->value.uint32_bool_value, &low_word, 4); - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } + memcpy(&result->value.uint32_bool_value, &low_word, 4); } else if (d_type->traits.numeric.scalar.width ==64) { uint32_t high_word; CHECKED_READU32(p_parser, p_node->word_offset + 4, high_word); uint64_t combined = low_word | (((uint64_t)high_word) << 32); - if (g_type == SPV_REFLECT_SCALAR_TYPE_FLOAT) { - memcpy(&result->value.float64_value, &combined, 8); - } - else if (g_type == SPV_REFLECT_SCALAR_TYPE_INT) { - if (d_type->traits.numeric.scalar.signedness) { - memcpy(&result->value.sint64_value, &combined, 8); - } - else { - memcpy(&result->value.uint64_value, &combined, 8); - } - } - else { - //memcpy(&result->value.uint32_bool_value, &combined, 8); - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } + memcpy(&result->value.uint64_value, &combined, 8); } else { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; @@ -5308,7 +5280,10 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint return res; } -// used for calculating specialization constants. +// Used for calculating specialization constants. +// The switches are not necessary for littel endian cpu, +// but still there just in case. +// memcpy is required since c/c++ have strict aliasing rules SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint32_t result_id, SpvReflectValue* result, uint32_t maxRecursion) { if(!maxRecursion) return SPV_REFLECT_RESULT_ERROR_SPIRV_RECURSION; @@ -5399,7 +5374,7 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint // check result type if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } // get operand @@ -5478,8 +5453,8 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint } } } - return SPV_REFLECT_RESULT_SUCCESS; } + return SPV_REFLECT_RESULT_SUCCESS; case SpvOpUConvert: { // convert of unsigned integer to any integer of different width. @@ -5488,7 +5463,7 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint // check result type if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } // get operand @@ -5567,8 +5542,8 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint } } } - return SPV_REFLECT_RESULT_SUCCESS; } + return SPV_REFLECT_RESULT_SUCCESS; case SpvOpFConvert: { // convert of floating point integer to any integer of different width. @@ -5576,7 +5551,7 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint // check result type if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_FLOAT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } // get operand @@ -5631,15 +5606,15 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint } } } - return SPV_REFLECT_RESULT_SUCCESS; } + return SPV_REFLECT_RESULT_SUCCESS; case SpvOpSNegate: { // compute minus sign of op1, not in current spec of what happens if op1 is uint // check result type if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } // get operand @@ -5652,10 +5627,6 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } - // operand must be signed - if (!operand1.type->traits.numeric.scalar.signedness) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } // vector size must match uint32_t vec_size = 1; if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { @@ -5718,14 +5689,15 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint } } } - return SPV_REFLECT_RESULT_SUCCESS; + } + return SPV_REFLECT_RESULT_SUCCESS; case SpvOpNot: { // bitwise not of every component in op1, store into same width result. // check result type if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } // get operand @@ -5760,60 +5732,429 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint switch (operand1.type->traits.numeric.scalar.width) { default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; case 32: - // load data into uint32_t - uint32_t data; - if (operand1.type->traits.numeric.scalar.signedness) { - memcpy(&data, &operand1.values[i].value.sint32_value, 4); - } - else{ + { + // load data into uint32_t + uint32_t data; memcpy(&data, &operand1.values[i].value.uint32_bool_value, 4); - } - data ^= 0xffffffff; - // write to correct offset - if (result->type->traits.numeric.scalar.signedness) { - memcpy(&result->values[i].value.sint32_value, &data, 4); - } - else { + data ^= 0xffffffff; + // write to correct offset memcpy(&result->values[i].value.uint32_bool_value, &data, 4); } break; case 64: - // load data into uint64_t - uint64_t data; - if (operand1.type->traits.numeric.scalar.signedness) { - memcpy(&data, &operand1.values[i].value.sint64_value, 8); - } - else { + { + // load data into uint64_t + uint64_t data; memcpy(&data, &operand1.values[i].value.uint64_value, 8); - } - data ^= 0xffffffffffffffff; - // write to correct offset - if (result->type->traits.numeric.scalar.signedness) { - memcpy(&result->values[i].value.sint64_value, &data, 8); - } - else { + data ^= 0xffffffffffffffff; + // write to correct offset memcpy(&result->values[i].value.uint64_value, &data, 8); } break; } } - return SPV_REFLECT_RESULT_SUCCESS; - + } + return SPV_REFLECT_RESULT_SUCCESS; + case SpvOpIAdd: // integer add. + { + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + // check type here, remember undefined value and booleans with type == null + if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + uint32_t operand_id2; + CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); + SpvReflectValue operand2 = {0}; + res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + // check type here, remember undefined value and booleans with type == null + if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + // component width must be same + if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // vectors must be of same size + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + vec_size = result->type->traits.numeric.vector.component_count; + } + + // now do the job, width unknown but same, all three sign unkown + // but still, since spv defines signed integer as 2-compliment, + // so do recent c/cpp standard, directly adding uint should be enough. + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + { + // load data into uint32_t + uint32_t data1; + memcpy(&data1, &operand1.values[i].value.uint32_bool_value, 4); + uint32_t data2; + memcpy(&data2, &operand2.values[i].value.uint32_bool_value, 4); + uint32_t data = data1 + data2; + // write to correct offset + memcpy(&result->values[i].value.uint32_bool_value, &data, 4); + } + break; + case 64: + { + // load data into uint64_t + uint64_t data1; + memcpy(&data1, &operand1.values[i].value.uint64_value, 8); + uint64_t data2; + memcpy(&data2, &operand2.values[i].value.uint64_value, 8); + uint64_t data = data1 + data2; + // write to correct offset + memcpy(&result->values[i].value.uint64_value, &data, 8); + } + break; + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; case SpvOpISub: - // integer subtract + // integer subtract. + { + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + // check type here, remember undefined value and booleans with type == null + if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + uint32_t operand_id2; + CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); + SpvReflectValue operand2 = {0}; + res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + // check type here, remember undefined value and booleans with type == null + if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // component width must be same + if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // vectors must be of same size + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + vec_size = result->type->traits.numeric.vector.component_count; + } + + // now do the job, width unknown but same, all three sign unkown + // but still, since spv defines signed integer as 2-compliment, + // so do recent c/cpp standard, directly adding uint should be enough. + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + { + // load data into uint32_t + uint32_t data1; + memcpy(&data1, &operand1.values[i].value.uint32_bool_value, 4); + uint32_t data2; + memcpy(&data2, &operand2.values[i].value.uint32_bool_value, 4); + uint32_t data = data1 - data2; + // write to correct offset + memcpy(&result->values[i].value.uint32_bool_value, &data, 4); + } + break; + case 64: + { + // load data into uint64_t + uint64_t data1; + memcpy(&data1, &operand1.values[i].value.uint64_value, 8); + uint64_t data2; + memcpy(&data2, &operand2.values[i].value.uint64_value, 8); + uint64_t data = data1 - data2; + // write to correct offset + memcpy(&result->values[i].value.uint64_value, &data, 8); + } + break; + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; case SpvOpIMul: - // integer multiply - + // integer multiply... + // what excactly will happen if int64 x uint64 is unspecified + // (consider overflow of negeative numbers... 2-compliment for "enough precision to avoid overflow and underflow" is not defined) + // this just assumes that negative overflow is behavior is same as whatever is emitted by compiler + // (likely imul on x86, which works on twice the size register and leave the latter half alone) + { + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + // check type here, remember undefined value and booleans with type == null + if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + uint32_t operand_id2; + CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); + SpvReflectValue operand2 = {0}; + res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + // check type here, remember undefined value and booleans with type == null + if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // component width must be same + if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // vectors must be of same size + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + vec_size = result->type->traits.numeric.vector.component_count; + } + + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + { + // load data into uint32_t + int32_t data1; + memcpy(&data1, &operand1.values[i].value.sint32_value, 4); + int32_t data2; + memcpy(&data2, &operand2.values[i].value.sint32_value, 4); + int32_t data = data1 * data2; + // write to correct offset + memcpy(&result->values[i].value.sint32_value, &data, 4); + } + break; + case 64: + { + // load data into uint64_t + int64_t data1; + memcpy(&data1, &operand1.values[i].value.sint64_value, 8); + int64_t data2; + memcpy(&data2, &operand2.values[i].value.sint64_value, 8); + int64_t data = data1 * data2; + // write to correct offset + memcpy(&result->values[i].value.sint64_value, &data, 8); + } + break; + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; case SpvOpUDiv: // unsigned divide + // All operand must be same unsigned integer scalar or vector type. + // x86 div instruction + { + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (result->type->traits.numeric.scalar.signedness) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + if (operand1.type != result->type) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + uint32_t operand_id2; + CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); + SpvReflectValue operand2 = {0}; + res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + if (operand1.type != result->type) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + vec_size = result->type->traits.numeric.vector.component_count; + } + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + { + result->values[i].value.uint32_bool_value = operand1.values[i].value.uint32_bool_value/ operand2.values[i].value.uint32_bool_value; + if (operand2.values[i].value.uint32_bool_value == 0) { + result->values[i].undefined_value = 1; + } + } + break; + case 64: + { + result->values[i].value.uint64_value = operand1.values[i].value.uint64_value / operand2.values[i].value.uint64_value; + if (operand2.values[i].value.uint64_value == 0) { + result->values[i].undefined_value = 1; + } + } + break; + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; case SpvOpSDiv: // signed divide + // same bits, same vector size, no sign requirements. + // x86 idiv instruction + { + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + uint32_t operand_id2; + CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); + SpvReflectValue operand2 = {0}; + res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // component width must be same + if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // vectors must be of same size + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + vec_size = result->type->traits.numeric.vector.component_count; + } + + for (uint32_t i = 0; i < vec_size; ++i) { + } + } + return SPV_REFLECT_RESULT_SUCCESS; case SpvOpUMod: case SpvOpSRem: case SpvOpSMod: case SpvOpShiftRightLogical: case SpvOpShiftRightArithmetic: case SpvOpShiftLeftLogical: case SpvOpBitwiseOr: case SpvOpBitwiseXor: @@ -5849,6 +6190,7 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint } } + } } diff --git a/spirv_reflect.h b/spirv_reflect.h index f5dd32cc..a9f8eb2e 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -40,6 +40,7 @@ VERSION HISTORY #include #include + #ifdef _MSC_VER #define SPV_REFLECT_DEPRECATED(msg_str) __declspec(deprecated("This symbol is deprecated. Details: " msg_str)) #elif defined(__clang__) @@ -349,6 +350,8 @@ typedef enum SpvReflectScalarType { } SpvReflectScalarType; // 16 bit floating point can be common. Just a bitwise representation here... +// c++ requires c++14 standard for non static union members to have same address. +// c seems to have always assumed this. typedef uint16_t spv_reflect_float16_t; typedef struct SpvReflectScalarValue { // strongly typed for evaluation purpose From 65eabd4d3d4ee2d0fbb4edf547cefda911e8af7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sat, 30 Jul 2022 16:52:45 +0800 Subject: [PATCH 05/44] Most arithmetic operations for integers are here. Vector composition and logical (boolean) ops left... --- spirv_reflect.c | 964 +++++++++++++++++++++++++++++++++++++++++++++--- spirv_reflect.h | 1 + 2 files changed, 916 insertions(+), 49 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index b950a32a..cc90fd67 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -5284,6 +5284,8 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint // The switches are not necessary for littel endian cpu, // but still there just in case. // memcpy is required since c/c++ have strict aliasing rules +// access to signed and unsigned versions of same width integer's +// address does not violate strict aliasing rules SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint32_t result_id, SpvReflectValue* result, uint32_t maxRecursion) { if(!maxRecursion) return SPV_REFLECT_RESULT_ERROR_SPIRV_RECURSION; @@ -5609,9 +5611,11 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint } return SPV_REFLECT_RESULT_SUCCESS; case SpvOpSNegate: + // compute minus sign of op1, reading from uint type union member + // currently violates strict aliasing rules... + // same as neg instruction. + // same bitwise not operation and then add 1 { - // compute minus sign of op1, not in current spec of what happens if op1 is uint - // check result type if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; @@ -5627,6 +5631,12 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } + + // component size must match. + if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + // vector size must match uint32_t vec_size = 1; if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { @@ -5646,55 +5656,33 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; case 32: // convert int32 to generic integer type - switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - if (result->type->traits.numeric.scalar.signedness) { - result->values[i].value.sint32_value = -operand1.values[i].value.sint32_value; - } - else { - result->values[i].value.uint32_bool_value = (uint32_t)(-operand1.values[i].value.sint32_value); - } - break; - case 64: - if (result->type->traits.numeric.scalar.signedness) { - result->values[i].value.sint64_value = -(int64_t)operand1.values[i].value.sint32_value; - } - else { - result->values[i].value.uint64_value = (uint64_t)(-operand1.values[i].value.sint32_value); - } - break; + { + // load data, strict aliasing rules require this memcpy + // reading from uint32_bool_value without memcpy may still violate strict aliasing rules? + int32_t data; + memcpy(&data, &operand1.values[i].value.sint32_value, 4); + data = -data; + memcpy(&result->values[i].value.sint32_value, &data, 4); } break; case 64: // convert int64 to generic integer type - switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - if (result->type->traits.numeric.scalar.signedness) { - result->values[i].value.sint32_value = (int32_t)(-operand1.values[i].value.sint64_value); - } - else { - result->values[i].value.uint32_bool_value = (uint32_t)(-operand1.values[i].value.sint64_value); - } - break; - case 64: - if (result->type->traits.numeric.scalar.signedness) { - result->values[i].value.sint64_value = -operand1.values[i].value.sint64_value; - } - else { - result->values[i].value.uint64_value = (uint64_t)(-operand1.values[i].value.sint64_value); - } - break; + { + // load data, strict aliasing rules require this memcpy + // reading from uint32_t without memcpy may still violate strict aliasing rules? + int64_t data; + memcpy(&data, &operand1.values[i].value.sint64_value, 8); + data = -data; + memcpy(&result->values[i].value.sint64_value, &data, 8); } + break; } } } return SPV_REFLECT_RESULT_SUCCESS; case SpvOpNot: + // bitwise not of every component in op1, store into same width result. { - // bitwise not of every component in op1, store into same width result. - // check result type if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; @@ -5758,6 +5746,7 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint case SpvOpIAdd: // integer add. + // subtraction result is the same for 2-compliment { // check result type if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { @@ -5850,6 +5839,7 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint return SPV_REFLECT_RESULT_SUCCESS; case SpvOpISub: // integer subtract. + // subtraction result is the same for 2-compliment { // check result type if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { @@ -5942,10 +5932,8 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint return SPV_REFLECT_RESULT_SUCCESS; case SpvOpIMul: // integer multiply... - // what excactly will happen if int64 x uint64 is unspecified - // (consider overflow of negeative numbers... 2-compliment for "enough precision to avoid overflow and underflow" is not defined) - // this just assumes that negative overflow is behavior is same as whatever is emitted by compiler - // (likely imul on x86, which works on twice the size register and leave the latter half alone) + // imul instruction on x86, signed and unsigned have no difference in result + // except for how they overflow. { // check result type if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { @@ -6037,6 +6025,7 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint // unsigned divide // All operand must be same unsigned integer scalar or vector type. // x86 div instruction + // emits undefined value if divide by zero { // check result type if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { @@ -6097,8 +6086,13 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint return SPV_REFLECT_RESULT_SUCCESS; case SpvOpSDiv: // signed divide - // same bits, same vector size, no sign requirements. // x86 idiv instruction + // same bits, same vector size, no sign requirements. + // accessing result types that are not signed violates strict aliasing rules. + // emits undefined value if divide by zero or 0x80000... divides -1 + // using just the c operator / here. In C89 rounding is implementation defined, + // but in later standard, this means rounding to zero (idiv instruction). + // spirv spec have nothing to say about rounding... { // check result type if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { @@ -6149,16 +6143,888 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint } vec_size = result->type->traits.numeric.vector.component_count; } + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + { + int32_t data1; + memcpy(&data1, &operand1.values[i].value.sint32_value, 4); + int32_t data2; + memcpy(&data2, &operand1.values[i].value.sint32_value, 4); + if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { + result->values[i].undefined_value = 1; + } + int32_t data = data1/data2; + memcpy(&result->values[i].value.sint32_value, &data, 4); + } + break; + case 64: + { + int64_t data1; + memcpy(&data1, &operand1.values[i].value.sint64_value, 8); + int64_t data2; + memcpy(&data2, &operand1.values[i].value.sint64_value, 8); + if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { + result->values[i].undefined_value = 1; + } + int64_t data = data1 / data2; + memcpy(&result->values[i].value.sint32_value, &data, 8); + } + break; + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; + case SpvOpUMod: + // unsigned modulo + // all types must be same unsigned integer scalar or vector type. + { + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (result->type->traits.numeric.scalar.signedness) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + if (operand1.type != result->type) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + uint32_t operand_id2; + CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); + SpvReflectValue operand2 = {0}; + res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + if (operand1.type != result->type) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + vec_size = result->type->traits.numeric.vector.component_count; + } for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + { + result->values[i].value.uint32_bool_value = operand1.values[i].value.uint32_bool_value % operand2.values[i].value.uint32_bool_value; + if (operand2.values[i].value.uint32_bool_value == 0) { + result->values[i].undefined_value = 1; + } + } + break; + case 64: + { + result->values[i].value.uint64_value = operand1.values[i].value.uint64_value % operand2.values[i].value.uint64_value; + if (operand2.values[i].value.uint64_value == 0) { + result->values[i].undefined_value = 1; + } + } + break; + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; + case SpvOpSRem: + // just the result of % operator. + { + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + uint32_t operand_id2; + CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); + SpvReflectValue operand2 = {0}; + res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // component width must be same + if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + // vectors must be of same size + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + vec_size = result->type->traits.numeric.vector.component_count; + } + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + { + int32_t data1; + memcpy(&data1, &operand1.values[i].value.sint32_value, 4); + int32_t data2; + memcpy(&data2, &operand1.values[i].value.sint32_value, 4); + if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { + result->values[i].undefined_value = 1; + } + int32_t data = data1 % data2; + memcpy(&result->values[i].value.sint32_value, &data, 4); + } + break; + case 64: + { + int64_t data1; + memcpy(&data1, &operand1.values[i].value.sint64_value, 8); + int64_t data2; + memcpy(&data2, &operand1.values[i].value.sint64_value, 8); + if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { + result->values[i].undefined_value = 1; + } + int64_t data = data1 % data2; + memcpy(&result->values[i].value.sint64_value, &data, 8); + } + break; + } } } return SPV_REFLECT_RESULT_SUCCESS; - case SpvOpUMod: case SpvOpSRem: case SpvOpSMod: - case SpvOpShiftRightLogical: case SpvOpShiftRightArithmetic: - case SpvOpShiftLeftLogical: case SpvOpBitwiseOr: case SpvOpBitwiseXor: - case SpvOpBitwiseAnd: case SpvOpVectorShuffle: case SpvOpCompositeExtract: + case SpvOpSMod: + // not result of % operator, need adjusting with dividend... + { + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + uint32_t operand_id2; + CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); + SpvReflectValue operand2 = {0}; + res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // component width must be same + if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // vectors must be of same size + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + vec_size = result->type->traits.numeric.vector.component_count; + } + + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + { + int32_t data1; + memcpy(&data1, &operand1.values[i].value.sint32_value, 4); + int32_t data2; + memcpy(&data2, &operand1.values[i].value.sint32_value, 4); + if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { + result->values[i].undefined_value = 1; + } + int32_t data = data1 % data2; + // multiplying data and data2 may result in overflow... + // need expicit tests... + if (data != 0) { + int sign1 = 0, sign2 = 0; + if (data < 0) sign1 = 1; + if (data2 < 0) sign2 = 1; + // remainder is not same as modulo here... + if ((sign1 + sign2) == 1) { + data += data2; + } + } + memcpy(&result->values[i].value.sint32_value, &data, 4); + } + break; + case 64: + { + int64_t data1; + memcpy(&data1, &operand1.values[i].value.sint64_value, 8); + int64_t data2; + memcpy(&data2, &operand1.values[i].value.sint64_value, 8); + if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { + result->values[i].undefined_value = 1; + } + int64_t data = data1 % data2; + // multiplying data and data2 may result in overflow... + // need expicit tests... + if (data != 0) { + int sign1 = 0, sign2 = 0; + if (data < 0) sign1 = 1; + if (data2 < 0) sign2 = 1; + // remainder is not same as modulo here... + if ((sign1 + sign2) == 1) { + data += data2; + } + } + memcpy(&result->values[i].value.sint64_value, &data, 8); + } + break; + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; + case SpvOpShiftRightLogical: + // zero fill right shift. Just >> in c + { + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + uint32_t operand_id2; + CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); + SpvReflectValue operand2 = {0}; + res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // op1 and result must have same width + if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + uint32_t res_width = result->type->traits.numeric.scalar.width; + + // vectors must be of same size + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + vec_size = result->type->traits.numeric.vector.component_count; + } + + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + // load the shift number, set undefined flag if larger than result width + uint8_t shift_num; + switch (operand2.type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + { + uint32_t shift; + memcpy(&shift, &operand2.values[i].value.uint32_bool_value, 4); + if (shift >= res_width) { + result->values[i].undefined_value = 1; + } + shift_num = (uint8_t)shift; + } + break; + case 64: + { + uint64_t shift; + memcpy(&shift, &operand2.values[i].value.uint32_bool_value, 8); + if (shift >= res_width) { + result->values[i].undefined_value = 1; + } + shift_num = (uint8_t)shift; + } + break; + } + switch (res_width) { + default: + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + { + uint32_t data; + memcpy(&data, &operand1.values[i].value.uint32_bool_value, 4); + data >>= shift_num; + memcpy(&result->values[i].value.uint32_bool_value, &data, 4); + } + break; + case 64: + { + uint64_t data; + memcpy(&data, &operand1.values[i].value.uint64_value, 8); + data >>= shift_num; + memcpy(&result->values[i].value.uint64_value, &data, 8); + } + break; + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; + case SpvOpShiftRightArithmetic: + // fill with sign of original number. + { + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + uint32_t operand_id2; + CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); + SpvReflectValue operand2 = {0}; + res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // op1 and result must have same width + if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + uint32_t res_width = result->type->traits.numeric.scalar.width; + + // vectors must be of same size + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + vec_size = result->type->traits.numeric.vector.component_count; + } + + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + // load the shift number, set undefined flag if larger than result width + uint8_t shift_num; + switch (operand2.type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + { + uint32_t shift; + memcpy(&shift, &operand2.values[i].value.uint32_bool_value, 4); + if (shift >= res_width) { + result->values[i].undefined_value = 1; + } + shift_num = (uint8_t)shift; + } + break; + case 64: + { + uint64_t shift; + memcpy(&shift, &operand2.values[i].value.uint32_bool_value, 8); + if (shift >= res_width) { + result->values[i].undefined_value = 1; + } + shift_num = (uint8_t)shift; + } + break; + } + switch (res_width) { + default: + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + { + uint32_t data; + memcpy(&data, &operand1.values[i].value.uint32_bool_value, 4); + uint32_t sign_bit = data & 0x80000000; + data >>= shift_num; + if (sign_bit) { + uint32_t fill = 0xffffffff << (32 - shift_num); + data |= fill; + } + memcpy(&result->values[i].value.uint32_bool_value, &data, 4); + } + break; + case 64: + { + uint64_t data; + memcpy(&data, &operand1.values[i].value.uint64_value, 8); + uint64_t sign_bit = data & 0x8000000000000000; + data >>= shift_num; + if (sign_bit) { + uint64_t fill = 0xffffffffffffffff << (64 - shift_num); + data |= fill; + } + memcpy(&result->values[i].value.uint64_value, &data, 8); + } + break; + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; + case SpvOpShiftLeftLogical: + { + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + uint32_t operand_id2; + CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); + SpvReflectValue operand2 = {0}; + res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // op1 and result must have same width + if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + uint32_t res_width = result->type->traits.numeric.scalar.width; + + // vectors must be of same size + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + vec_size = result->type->traits.numeric.vector.component_count; + } + + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + // load the shift number, set undefined flag if larger than result width + uint8_t shift_num; + switch (operand2.type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + { + uint32_t shift; + memcpy(&shift, &operand2.values[i].value.uint32_bool_value, 4); + if (shift >= res_width) { + result->values[i].undefined_value = 1; + } + shift_num = (uint8_t)shift; + } + break; + case 64: + { + uint64_t shift; + memcpy(&shift, &operand2.values[i].value.uint32_bool_value, 8); + if (shift >= res_width) { + result->values[i].undefined_value = 1; + } + shift_num = (uint8_t)shift; + } + break; + } + switch (res_width) { + default: + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + { + uint32_t data; + memcpy(&data, &operand1.values[i].value.uint32_bool_value, 4); + data <<= shift_num; + memcpy(&result->values[i].value.uint32_bool_value, &data, 4); + } + break; + case 64: + { + uint64_t data; + memcpy(&data, &operand1.values[i].value.uint64_value, 8); + data <<= shift_num; + memcpy(&result->values[i].value.uint64_value, &data, 8); + } + break; + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; + case SpvOpBitwiseOr: + { + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + // check type here, remember undefined value and booleans with type == null + if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + uint32_t operand_id2; + CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); + SpvReflectValue operand2 = {0}; + res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + // check type here, remember undefined value and booleans with type == null + if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // component width must be same + if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // vectors must be of same size + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + vec_size = result->type->traits.numeric.vector.component_count; + } + + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + { + // load data into uint32_t + uint32_t data1; + memcpy(&data1, &operand1.values[i].value.uint32_bool_value, 4); + uint32_t data2; + memcpy(&data2, &operand2.values[i].value.uint32_bool_value, 4); + uint32_t data = data1 | data2; + // write to correct offset + memcpy(&result->values[i].value.uint32_bool_value, &data, 4); + } + break; + case 64: + { + // load data into uint64_t + uint64_t data1; + memcpy(&data1, &operand1.values[i].value.uint64_value, 8); + uint64_t data2; + memcpy(&data2, &operand2.values[i].value.uint64_value, 8); + uint64_t data = data1 | data2; + // write to correct offset + memcpy(&result->values[i].value.uint64_value, &data, 8); + } + break; + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; + case SpvOpBitwiseXor: + { + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + // check type here, remember undefined value and booleans with type == null + if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + uint32_t operand_id2; + CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); + SpvReflectValue operand2 = {0}; + res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + // check type here, remember undefined value and booleans with type == null + if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // component width must be same + if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // vectors must be of same size + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + vec_size = result->type->traits.numeric.vector.component_count; + } + + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + { + // load data into uint32_t + uint32_t data1; + memcpy(&data1, &operand1.values[i].value.uint32_bool_value, 4); + uint32_t data2; + memcpy(&data2, &operand2.values[i].value.uint32_bool_value, 4); + uint32_t data = data1 ^ data2; + // write to correct offset + memcpy(&result->values[i].value.uint32_bool_value, &data, 4); + } + break; + case 64: + { + // load data into uint64_t + uint64_t data1; + memcpy(&data1, &operand1.values[i].value.uint64_value, 8); + uint64_t data2; + memcpy(&data2, &operand2.values[i].value.uint64_value, 8); + uint64_t data = data1 ^ data2; + // write to correct offset + memcpy(&result->values[i].value.uint64_value, &data, 8); + } + break; + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; + case SpvOpBitwiseAnd: + { + // check result type + if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // get operand + uint32_t operand_id1; + CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); + SpvReflectValue operand1 = {0}; + res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + // check type here, remember undefined value and booleans with type == null + if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + uint32_t operand_id2; + CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); + SpvReflectValue operand2 = {0}; + res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + // check type here, remember undefined value and booleans with type == null + if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // component width must be same + if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // vectors must be of same size + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + vec_size = result->type->traits.numeric.vector.component_count; + } + + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + { + // load data into uint32_t + uint32_t data1; + memcpy(&data1, &operand1.values[i].value.uint32_bool_value, 4); + uint32_t data2; + memcpy(&data2, &operand2.values[i].value.uint32_bool_value, 4); + uint32_t data = data1 & data2; + // write to correct offset + memcpy(&result->values[i].value.uint32_bool_value, &data, 4); + } + break; + case 64: + { + // load data into uint64_t + uint64_t data1; + memcpy(&data1, &operand1.values[i].value.uint64_value, 8); + uint64_t data2; + memcpy(&data2, &operand2.values[i].value.uint64_value, 8); + uint64_t data = data1 & data2; + // write to correct offset + memcpy(&result->values[i].value.uint64_value, &data, 8); + } + break; + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; + case SpvOpVectorShuffle: + + case SpvOpCompositeExtract: case SpvOpCompositeInsert: case SpvOpLogicalOr: case SpvOpLogicalAnd: case SpvOpLogicalNot: case SpvOpLogicalEqual: case SpvOpLogicalNotEqual: diff --git a/spirv_reflect.h b/spirv_reflect.h index a9f8eb2e..f9b4d862 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -372,6 +372,7 @@ typedef struct SpvReflectScalarValue { typedef struct SpvReflectValue { SpvReflectScalarType general_type; // may be null if boolean, coming from OpSpecConstantTrue/OpSpecConstantFalse + // but type found through return type id is never null. SpvReflectTypeDescription* type; SpvReflectScalarValue values[SPV_REFLECT_MAX_VECTOR_DIMS]; } SpvReflectValue; From 4697ff665a1d180e8f659d7ffc3746d248da7922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sat, 30 Jul 2022 21:17:50 +0800 Subject: [PATCH 06/44] Move some expr to `#define` Code too lengthy, difficult to maintain... --- spirv_reflect.c | 2056 ++++++++++++----------------------------------- 1 file changed, 533 insertions(+), 1523 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index cc90fd67..ca45fea8 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -5280,6 +5280,335 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint return res; } +#include + +#define CHECK_INSTRUCTION_SIZE(node, expected) \ +{ \ + if (node->word_count != expected) { \ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; \ + } \ +} + +#define CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_result, p_op1) \ +{ \ + \ + if ((p_result)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + if (!((p_op1)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + } \ + if ((p_op1)->type->traits.numeric.vector.component_count != (p_result)->type->traits.numeric.vector.component_count) { \ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + } \ + vec_size = (p_result)->type->traits.numeric.vector.component_count; \ + } \ +} + +#define CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, p_result, p_op1, p_op2) \ +{ \ + \ + if ((p_result)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + if (!((p_op1)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + } \ + if (!((p_op2)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + } \ + if ((p_op1)->type->traits.numeric.vector.component_count != (p_result)->type->traits.numeric.vector.component_count) { \ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + } \ + if ((p_op2)->type->traits.numeric.vector.component_count != (p_result)->type->traits.numeric.vector.component_count) { \ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + } \ + vec_size = (p_result)->type->traits.numeric.vector.component_count; \ + } \ +} + +#define CHECK_WIDTH_MATCH(p_value1, p_value2) \ +{ \ + if ((p_value2)->type->traits.numeric.scalar.width != (p_value1)->type->traits.numeric.scalar.width) { \ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + } \ +} + +#define CHECK_IS_BASIC_TYPE_EXCEPT_BOOL(p_result, b_type) \ +{ \ + if(!(p_result)->type) { \ + /* is result of opconstanttrue, etc. Boolean... */ \ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + } \ + if(((p_result)->type->type_flags & SCALAR_TYPE_FLAGS) != b_type) { \ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + } \ +} + +#define CHECK_IS_INTEGER_TYPE(p_result) CHECK_IS_BASIC_TYPE_EXCEPT_BOOL(p_result, SPV_REFLECT_TYPE_FLAG_INT) +#define CHECK_IS_FLOAT_TYPE(p_result) CHECK_IS_BASIC_TYPE_EXCEPT_BOOL(p_result, SPV_REFLECT_TYPE_FLAG_FLOAT) +#define CHECK_IS_BOOLEAN_TYPE(p_result) \ +{ \ + if((p_result)->type) { \ + if(((p_result)->type->type_flags & SCALAR_TYPE_FLAGS) != b_type) { \ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + } \ + } \ +} + +#define GET_OPERAND(p_module, p_node, offset, p_operand, maxRecursion) \ +{ \ + uint32_t operand_id; \ + CHECKED_READU32(p_module->_internal->parser, p_node->word_offset + offset, operand_id); \ + SpvReflectResult result_get_op = EvaluateResultImpl(p_module, operand_id, (p_operand), maxRecursion - 1); \ + if (result_get_op != SPV_REFLECT_RESULT_SUCCESS) return result_get_op; \ +} + +#define SIMPLE_UNARY_OP_32_BIT_HOOK +#define SIMPLE_UNARY_OP_64_BIT_HOOK + +#define DO_SIMPLE_UNARY_INTEGER_OPERATION(p_result, simple_op_module, simple_op_node, maxRecursion) \ +{ \ + CHECK_INSTRUCTION_SIZE((simple_op_node), 5) \ + \ + /* check result type */ \ + CHECK_IS_INTEGER_TYPE((p_result)) \ + \ + /* get operand */ \ + SpvReflectValue operand1 = {0}; \ + GET_OPERAND((simple_op_module), (simple_op_node), 4, &operand1, maxRecursion) \ + /* check type here */ \ + CHECK_IS_INTEGER_TYPE(&operand1) \ + \ + /* component width must match. */ \ + CHECK_WIDTH_MATCH((p_result), &operand1) \ + \ + /* vector size must match */ \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, (p_result), &operand1) \ + \ + /* now do the job */ \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + (p_result)->values[i].undefined_value = operand1.values->undefined_value; \ + switch (operand1.type->traits.numeric.scalar.width) { \ + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + case 32: \ + /* 32 bit integer */ \ + { \ + int32_t data = operand1.values[i].value.sint32_value; \ + SIMPLE_UNARY_OP_32_BIT_HOOK \ + (p_result)->values[i].value.sint32_value = data; \ + } \ + break; \ + case 64: \ + /* 64 bit integer */ \ + { \ + int64_t data = operand1.values[i].value.sint64_value; \ + SIMPLE_UNARY_OP_64_BIT_HOOK \ + (p_result)->values[i].value.sint64_value = data; \ + } \ + break; \ + } \ + } \ + return SPV_REFLECT_RESULT_SUCCESS; \ +} + +#define SIMPLE_BINARY_OP_32_BIT_HOOK +#define SIMPLE_BINARY_OP_64_BIT_HOOK + +#define DO_SIMPLE_BINARY_INTEGER_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion) \ +{ \ + { \ + CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ + /* check result type*/ \ + CHECK_IS_INTEGER_TYPE(p_result) \ + \ + /* get operand */ \ + SpvReflectValue operand1 = {0}; \ + GET_OPERAND(simple_op_module, simple_op_node, 4, &operand1, maxRecursion) \ + CHECK_IS_INTEGER_TYPE(&operand1) \ + \ + SpvReflectValue operand2 = {0}; \ + GET_OPERAND(simple_op_module, simple_op_node, 5, &operand2, maxRecursion) \ + CHECK_IS_INTEGER_TYPE(&operand2) \ + \ + /* component width must be same */ \ + CHECK_WIDTH_MATCH(p_result, &operand1) \ + CHECK_WIDTH_MATCH(p_result, &operand2) \ + \ + /* vectors must be of same size */ \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, p_result, &operand1, &operand2) \ + /* now do the job, width unknown but same, all three sign unkown \ + but still, since spv defines signed integer as 2-compliment, \ + so do recent c/cpp standard, directly adding uint should be enough.*/ \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { \ + (p_result)->values[i].undefined_value = 1; \ + } \ + switch ((p_result)->type->traits.numeric.scalar.width) { \ + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + case 32: \ + { \ + /* load data into int32_t*/ \ + int32_t data1 = operand1.values[i].value.sint32_value; \ + int32_t data2 = operand2.values[i].value.sint32_value; \ + int32_t data = data1 operation data2; \ + SIMPLE_BINARY_OP_32_BIT_HOOK \ + /* write to correct offset */ \ + (p_result)->values[i].value.sint32_value = data; \ + } \ + break; \ + case 64: \ + { \ + /* load data into int64_t*/ \ + int64_t data1 = operand1.values[i].value.sint64_value; \ + int64_t data2 = operand2.values[i].value.sint64_value; \ + int64_t data = data1 operation data2; \ + SIMPLE_BINARY_OP_32_BIT_HOOK \ + /* write to correct offset */ \ + (p_result)->values[i].value.sint64_value = data; \ + } \ + break; \ + } \ + } \ + } \ + return SPV_REFLECT_RESULT_SUCCESS; \ +} + +#define DO_UNSIGNED_INTEGER_DIVISION(p_result, simple_op_module, simple_op_node, operation, maxRecursion) \ +{ \ + CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ + /* check result type */ \ + CHECK_IS_INTEGER_TYPE(result) \ + if ((p_result)->type->traits.numeric.scalar.signedness) { \ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + } \ + \ + /* get operand */ \ + SpvReflectValue operand1 = {0}; \ + GET_OPERAND(simple_op_module, simple_op_node, 4, &operand1, maxRecursion) \ + \ + if (operand1.type != (p_result)->type) { \ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + } \ + SpvReflectValue operand2 = {0}; \ + GET_OPERAND(simple_op_module, simple_op_node, 5, &operand2, maxRecursion) \ + if (operand1.type != (p_result)->type) { \ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + } \ + \ + uint32_t vec_size = 1; \ + if ((p_result)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + vec_size = result->type->traits.numeric.vector.component_count; \ + } \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { \ + (p_result)->values[i].undefined_value = 1; \ + } \ + switch ((p_result)->type->traits.numeric.scalar.width) { \ + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + case 32: \ + { \ + (p_result)->values[i].value.uint32_bool_value \ + = operand1.values[i].value.uint32_bool_value operation operand2.values[i].value.uint32_bool_value; \ + if (operand2.values[i].value.uint32_bool_value == 0) { \ + (p_result)->values[i].undefined_value = 1; \ + } \ + } \ + break; \ + case 64: \ + { \ + (p_result)->values[i].value.uint64_value \ + = operand1.values[i].value.uint64_value operation operand2.values[i].value.uint64_value; \ + if (operand2.values[i].value.uint64_value == 0) { \ + (p_result)->values[i].undefined_value = 1; \ + } \ + } \ + break; \ + } \ + } \ + return SPV_REFLECT_RESULT_SUCCESS; \ +} + +#define SHIFT_OP_32_BIT_HOOK_PRE +#define SHIFT_OP_64_BIT_HOOK_PRE +#define SHIFT_OP_32_BIT_HOOK_POST +#define SHIFT_OP_64_BIT_HOOK_POST + +#define DO_SHIFT_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion) \ +{ \ + CHECK_INSTRUCTION_SIZE((simple_op_node), 6) \ + /* check result type */ \ + CHECK_IS_INTEGER_TYPE((p_result)) \ + \ + /* get operand */ \ + SpvReflectValue operand1 = {0}; \ + GET_OPERAND((simple_op_module), (simple_op_node), 4, &operand1, maxRecursion) \ + CHECK_IS_INTEGER_TYPE(&operand1) \ + \ + SpvReflectValue operand2 = {0}; \ + GET_OPERAND((simple_op_module), (simple_op_node), 5, &operand2, maxRecursion) \ + CHECK_IS_INTEGER_TYPE(&operand2) \ + \ + /* op1 and result must have same width */ \ + CHECK_WIDTH_MATCH((p_result), &operand1) \ + uint32_t res_width = (p_result)->type->traits.numeric.scalar.width; \ + \ + /* vectors must be of same size */ \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), &operand1, &operand2); \ + \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { \ + (p_result)->values[i].undefined_value = 1; \ + } \ + /* load the shift number, set undefined flag if larger than result width*/ \ + uint8_t shift_num; \ + switch (operand2.type->traits.numeric.scalar.width) { \ + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + case 32: \ + { \ + uint32_t shift = operand2.values[i].value.uint32_bool_value; \ + if (operand1.values[i].undefined_value || shift >= res_width) { \ + (p_result)->values[i].undefined_value = 1; \ + } \ + shift_num = (uint8_t)shift; \ + } \ + break; \ + case 64: \ + { \ + uint64_t shift = operand2.values[i].value.uint64_value; \ + if (operand1.values[i].undefined_value || shift >= res_width) { \ + (p_result)->values[i].undefined_value = 1; \ + } \ + shift_num = (uint8_t)shift; \ + } \ + break; \ + } \ + switch (res_width) { \ + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + case 32: \ + { \ + uint32_t data = operand1.values[i].value.uint32_bool_value; \ + SHIFT_OP_32_BIT_HOOK_PRE \ + data operation##= shift_num; \ + SHIFT_OP_32_BIT_HOOK_POST \ + (p_result)->values[i].value.uint32_bool_value = data; \ + } \ + break; \ + case 64: \ + { \ + uint64_t data = operand1.values[i].value.uint64_value; \ + SHIFT_OP_64_BIT_HOOK_PRE \ + data operation##= shift_num; \ + SHIFT_OP_64_BIT_HOOK_POST \ + (p_result)->values[i].value.uint64_value = data; \ + } \ + break; \ + } \ + } \ + return SPV_REFLECT_RESULT_SUCCESS; \ +} + + + // Used for calculating specialization constants. // The switches are not necessary for littel endian cpu, // but still there just in case. @@ -5351,12 +5680,13 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint // evaluate op uint32_t spec_op; CHECKED_READU32(p_parser, p_node->word_offset + 3, spec_op); - spec_op &= 0xFFFF; switch (spec_op) { default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; case SpvOpUndef: + // write undefined value to result... { + CHECK_INSTRUCTION_SIZE(p_node, 4) if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { for (uint32_t i = 0; i < result->type->traits.numeric.vector.component_count; ++i) { result->values[i].undefined_value = 1; @@ -5368,42 +5698,26 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint } return SPV_REFLECT_RESULT_SUCCESS; case SpvOpSConvert: - // maybe there's a more clever way? + // sign extend or truncate integers. + // result is scalar or vector integer type. + // vectors should be of same length { - // convert of signed integer to any integer of different width. - // result is scalar or vector integer type. - // vectors should be of same length + CHECK_INSTRUCTION_SIZE(p_node, 5) // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } + CHECK_IS_INTEGER_TYPE(result) // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - // check type here, remember undefined value and booleans with type == null - if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } + GET_OPERAND(p_module, p_node, 4, &operand1, maxRecursion) + CHECK_IS_INTEGER_TYPE(&operand1) // operand must be signed if (!operand1.type->traits.numeric.scalar.signedness) { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } // vector size must match uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - vec_size = operand1.type->traits.numeric.vector.component_count; - } + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, result, &operand1) // now do the job for (uint32_t i = 0; i < vec_size; ++i) { @@ -5411,88 +5725,60 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint switch (operand1.type->traits.numeric.scalar.width) { default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; case 32: - // convert int32 to generic integer type - switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - if (result->type->traits.numeric.scalar.signedness) { - result->values[i].value.sint32_value = operand1.values[i].value.sint32_value; - } - else { - result->values[i].value.uint32_bool_value = (uint32_t)operand1.values[i].value.sint32_value; - } - break; - case 64: - if (result->type->traits.numeric.scalar.signedness) { - result->values[i].value.sint64_value = (int64_t)operand1.values[i].value.sint32_value; - } - else { - result->values[i].value.uint64_value = (uint64_t)operand1.values[i].value.sint32_value; - } - break; + { + int32_t data = operand1.values[i].value.sint32_value; + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + result->values[i].value.sint32_value = data; + break; + case 64: + result->values[i].value.sint64_value = (int64_t)data; + break; + } } break; case 64: - // convert int64 to generic integer type - switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - if (result->type->traits.numeric.scalar.signedness) { - result->values[i].value.sint32_value = (int32_t)operand1.values[i].value.sint64_value; - } - else { - result->values[i].value.uint32_bool_value = (uint32_t)operand1.values[i].value.sint64_value; - } - break; - case 64: - if (result->type->traits.numeric.scalar.signedness) { - result->values[i].value.sint64_value = operand1.values[i].value.sint64_value; - } - else { - result->values[i].value.uint64_value = (uint64_t)operand1.values[i].value.sint64_value; - } - break; + { + int64_t data = operand1.values[i].value.sint64_value; + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + result->values[i].value.sint32_value = (int32_t)data; + break; + case 64: + result->values[i].value.sint64_value = data; + break; + } } + break; } } } return SPV_REFLECT_RESULT_SUCCESS; case SpvOpUConvert: + // zero extend or truncate integers. + // result is scalar or vector integer type. + // vectors should be of same length { - // convert of unsigned integer to any integer of different width. - // result is scalar or vector integer type. - // vectors should be of same length + CHECK_INSTRUCTION_SIZE(p_node, 5) // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } + CHECK_IS_INTEGER_TYPE(result) // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + GET_OPERAND(p_module, p_node, 4, &operand1, maxRecursion) + // check type here, remember undefined value and booleans with type == null - if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } + CHECK_IS_INTEGER_TYPE(&operand1) // operand must not be signed if (operand1.type->traits.numeric.scalar.signedness) { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } // vector size must match uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - vec_size = operand1.type->traits.numeric.vector.component_count; - } + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, result, &operand1) // now do the job for (uint32_t i = 0; i < vec_size; ++i) { @@ -5500,83 +5786,55 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint switch (operand1.type->traits.numeric.scalar.width) { default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; case 32: - // convert int32 to generic integer type - switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - if (result->type->traits.numeric.scalar.signedness) { - result->values[i].value.sint32_value = operand1.values[i].value.uint32_bool_value; - } - else { - result->values[i].value.uint32_bool_value = (uint32_t)operand1.values[i].value.uint32_bool_value; - } - break; - case 64: - if (result->type->traits.numeric.scalar.signedness) { - result->values[i].value.sint64_value = (int64_t)operand1.values[i].value.uint32_bool_value; - } - else { - result->values[i].value.uint64_value = (uint64_t)operand1.values[i].value.uint32_bool_value; - } - break; + { + uint32_t data = operand1.values[i].value.uint32_bool_value; + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + result->values[i].value.uint32_bool_value = data; + break; + case 64: + result->values[i].value.uint64_value = (uint64_t)data; + break; + } } break; case 64: - // convert int64 to generic integer type - switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - if (result->type->traits.numeric.scalar.signedness) { - result->values[i].value.sint32_value = (int32_t)operand1.values[i].value.uint64_value; - } - else { - result->values[i].value.uint32_bool_value = (uint32_t)operand1.values[i].value.uint64_value; - } - break; - case 64: - if (result->type->traits.numeric.scalar.signedness) { - result->values[i].value.sint64_value = operand1.values[i].value.uint64_value; - } - else { - result->values[i].value.uint64_value = (uint64_t)operand1.values[i].value.uint64_value; - } - break; + { + uint64_t data = operand1.values[i].value.uint64_value; + switch (result->type->traits.numeric.scalar.width) { + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case 32: + result->values[i].value.uint32_bool_value = (uint32_t)data; + break; + case 64: + result->values[i].value.uint64_value = data; + break; + } } + break; } } } return SPV_REFLECT_RESULT_SUCCESS; case SpvOpFConvert: + // convert of floating point integer to any integer of different width. + // just 32 and 64 bit for now... { - // convert of floating point integer to any integer of different width. - // just 32 and 64 bit for now... + CHECK_INSTRUCTION_SIZE(p_node, 5) // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_FLOAT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } + CHECK_IS_FLOAT_TYPE(result) // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + GET_OPERAND(p_module, p_node, 4, &operand1, maxRecursion) + // check type here, remember undefined value and booleans with type == null - if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_FLOAT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } + CHECK_IS_FLOAT_TYPE(&operand1) // vector size must match uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - vec_size = operand1.type->traits.numeric.vector.component_count; - } + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, result, &operand1) // now do the job for (uint32_t i = 0; i < vec_size; ++i) { @@ -5611,1422 +5869,174 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint } return SPV_REFLECT_RESULT_SUCCESS; case SpvOpSNegate: - // compute minus sign of op1, reading from uint type union member - // currently violates strict aliasing rules... - // same as neg instruction. - // same bitwise not operation and then add 1 - { - // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); - SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - // check type here, remember undefined value and booleans with type == null - if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // component size must match. - if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // vector size must match - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - vec_size = operand1.type->traits.numeric.vector.component_count; - } - - // now do the job - for (uint32_t i = 0; i < vec_size; ++i) { - result->values[i].undefined_value = operand1.values->undefined_value; - switch (operand1.type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - // convert int32 to generic integer type - { - // load data, strict aliasing rules require this memcpy - // reading from uint32_bool_value without memcpy may still violate strict aliasing rules? - int32_t data; - memcpy(&data, &operand1.values[i].value.sint32_value, 4); - data = -data; - memcpy(&result->values[i].value.sint32_value, &data, 4); - } - break; - case 64: - // convert int64 to generic integer type - { - // load data, strict aliasing rules require this memcpy - // reading from uint32_t without memcpy may still violate strict aliasing rules? - int64_t data; - memcpy(&data, &operand1.values[i].value.sint64_value, 8); - data = -data; - memcpy(&result->values[i].value.sint64_value, &data, 8); - } - break; - } - } - } - return SPV_REFLECT_RESULT_SUCCESS; + #undef SIMPLE_UNARY_OP_32_BIT_HOOK + #undef SIMPLE_UNARY_OP_64_BIT_HOOK + #define SIMPLE_UNARY_OP_32_BIT_HOOK {data = -data;} + #define SIMPLE_UNARY_OP_64_BIT_HOOK {data = -data;} + DO_SIMPLE_UNARY_INTEGER_OPERATION(result, p_module, p_node, maxRecursion) + #undef SIMPLE_UNARY_OP_32_BIT_HOOK + #undef SIMPLE_UNARY_OP_64_BIT_HOOK + #define SIMPLE_UNARY_OP_32_BIT_HOOK + #define SIMPLE_UNARY_OP_64_BIT_HOOK case SpvOpNot: // bitwise not of every component in op1, store into same width result. - { - // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); - SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - // check type here, remember undefined value and booleans with type == null - if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - // width must match - if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - // vector size must match - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - vec_size = operand1.type->traits.numeric.vector.component_count; - } - - // now do the job - for (uint32_t i = 0; i < vec_size; ++i) { - result->values[i].undefined_value = operand1.values->undefined_value; - switch (operand1.type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - { - // load data into uint32_t - uint32_t data; - memcpy(&data, &operand1.values[i].value.uint32_bool_value, 4); - data ^= 0xffffffff; - // write to correct offset - memcpy(&result->values[i].value.uint32_bool_value, &data, 4); - } - break; - case 64: - { - // load data into uint64_t - uint64_t data; - memcpy(&data, &operand1.values[i].value.uint64_value, 8); - data ^= 0xffffffffffffffff; - // write to correct offset - memcpy(&result->values[i].value.uint64_value, &data, 8); - } - break; - } - } - } - return SPV_REFLECT_RESULT_SUCCESS; - + #undef SIMPLE_UNARY_OP_32_BIT_HOOK + #undef SIMPLE_UNARY_OP_64_BIT_HOOK + #define SIMPLE_UNARY_OP_32_BIT_HOOK data ^= 0xffffffff; + #define SIMPLE_UNARY_OP_64_BIT_HOOK data ^= 0xffffffffffffffff; + DO_SIMPLE_UNARY_INTEGER_OPERATION(result, p_module, p_node, maxRecursion) + #undef SIMPLE_UNARY_OP_32_BIT_HOOK + #undef SIMPLE_UNARY_OP_64_BIT_HOOK + #define SIMPLE_UNARY_OP_32_BIT_HOOK + #define SIMPLE_UNARY_OP_64_BIT_HOOK case SpvOpIAdd: // integer add. // subtraction result is the same for 2-compliment - { - // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); - SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - // check type here, remember undefined value and booleans with type == null - if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - uint32_t operand_id2; - CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); - SpvReflectValue operand2 = {0}; - res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - // check type here, remember undefined value and booleans with type == null - if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // component width must be same - if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // vectors must be of same size - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - vec_size = result->type->traits.numeric.vector.component_count; - } - - // now do the job, width unknown but same, all three sign unkown - // but still, since spv defines signed integer as 2-compliment, - // so do recent c/cpp standard, directly adding uint should be enough. - for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { - result->values[i].undefined_value = 1; - } - switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - { - // load data into uint32_t - uint32_t data1; - memcpy(&data1, &operand1.values[i].value.uint32_bool_value, 4); - uint32_t data2; - memcpy(&data2, &operand2.values[i].value.uint32_bool_value, 4); - uint32_t data = data1 + data2; - // write to correct offset - memcpy(&result->values[i].value.uint32_bool_value, &data, 4); - } - break; - case 64: - { - // load data into uint64_t - uint64_t data1; - memcpy(&data1, &operand1.values[i].value.uint64_value, 8); - uint64_t data2; - memcpy(&data2, &operand2.values[i].value.uint64_value, 8); - uint64_t data = data1 + data2; - // write to correct offset - memcpy(&result->values[i].value.uint64_value, &data, 8); - } - break; - } - } - } - return SPV_REFLECT_RESULT_SUCCESS; + DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, +, maxRecursion) case SpvOpISub: // integer subtract. // subtraction result is the same for 2-compliment - { - // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); - SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - // check type here, remember undefined value and booleans with type == null - if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - uint32_t operand_id2; - CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); - SpvReflectValue operand2 = {0}; - res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - // check type here, remember undefined value and booleans with type == null - if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // component width must be same - if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // vectors must be of same size - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - vec_size = result->type->traits.numeric.vector.component_count; - } - - // now do the job, width unknown but same, all three sign unkown - // but still, since spv defines signed integer as 2-compliment, - // so do recent c/cpp standard, directly adding uint should be enough. - for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { - result->values[i].undefined_value = 1; - } - switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - { - // load data into uint32_t - uint32_t data1; - memcpy(&data1, &operand1.values[i].value.uint32_bool_value, 4); - uint32_t data2; - memcpy(&data2, &operand2.values[i].value.uint32_bool_value, 4); - uint32_t data = data1 - data2; - // write to correct offset - memcpy(&result->values[i].value.uint32_bool_value, &data, 4); - } - break; - case 64: - { - // load data into uint64_t - uint64_t data1; - memcpy(&data1, &operand1.values[i].value.uint64_value, 8); - uint64_t data2; - memcpy(&data2, &operand2.values[i].value.uint64_value, 8); - uint64_t data = data1 - data2; - // write to correct offset - memcpy(&result->values[i].value.uint64_value, &data, 8); - } - break; - } - } - } - return SPV_REFLECT_RESULT_SUCCESS; + DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, -, maxRecursion) case SpvOpIMul: // integer multiply... // imul instruction on x86, signed and unsigned have no difference in result // except for how they overflow. - { - // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); - SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - // check type here, remember undefined value and booleans with type == null - if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - uint32_t operand_id2; - CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); - SpvReflectValue operand2 = {0}; - res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - // check type here, remember undefined value and booleans with type == null - if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // component width must be same - if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // vectors must be of same size - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - vec_size = result->type->traits.numeric.vector.component_count; - } - - for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { - result->values[i].undefined_value = 1; - } - switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - { - // load data into uint32_t - int32_t data1; - memcpy(&data1, &operand1.values[i].value.sint32_value, 4); - int32_t data2; - memcpy(&data2, &operand2.values[i].value.sint32_value, 4); - int32_t data = data1 * data2; - // write to correct offset - memcpy(&result->values[i].value.sint32_value, &data, 4); - } - break; - case 64: - { - // load data into uint64_t - int64_t data1; - memcpy(&data1, &operand1.values[i].value.sint64_value, 8); - int64_t data2; - memcpy(&data2, &operand2.values[i].value.sint64_value, 8); - int64_t data = data1 * data2; - // write to correct offset - memcpy(&result->values[i].value.sint64_value, &data, 8); - } - break; - } - } - } - return SPV_REFLECT_RESULT_SUCCESS; + DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, *, maxRecursion) case SpvOpUDiv: // unsigned divide // All operand must be same unsigned integer scalar or vector type. // x86 div instruction // emits undefined value if divide by zero - { - // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (result->type->traits.numeric.scalar.signedness) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); - SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - if (operand1.type != result->type) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - uint32_t operand_id2; - CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); - SpvReflectValue operand2 = {0}; - res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - if (operand1.type != result->type) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - vec_size = result->type->traits.numeric.vector.component_count; - } - for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { - result->values[i].undefined_value = 1; - } - switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - { - result->values[i].value.uint32_bool_value = operand1.values[i].value.uint32_bool_value/ operand2.values[i].value.uint32_bool_value; - if (operand2.values[i].value.uint32_bool_value == 0) { - result->values[i].undefined_value = 1; - } - } - break; - case 64: - { - result->values[i].value.uint64_value = operand1.values[i].value.uint64_value / operand2.values[i].value.uint64_value; - if (operand2.values[i].value.uint64_value == 0) { - result->values[i].undefined_value = 1; - } - } - break; - } - } - } - return SPV_REFLECT_RESULT_SUCCESS; + DO_UNSIGNED_INTEGER_DIVISION(result, p_module, p_node, /, maxRecursion) case SpvOpSDiv: // signed divide // x86 idiv instruction // same bits, same vector size, no sign requirements. // accessing result types that are not signed violates strict aliasing rules. // emits undefined value if divide by zero or 0x80000... divides -1 - // using just the c operator / here. In C89 rounding is implementation defined, - // but in later standard, this means rounding to zero (idiv instruction). - // spirv spec have nothing to say about rounding... - { - // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); - SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - uint32_t operand_id2; - CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); - SpvReflectValue operand2 = {0}; - res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // component width must be same - if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // vectors must be of same size - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - vec_size = result->type->traits.numeric.vector.component_count; - } - for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { - result->values[i].undefined_value = 1; - } - switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - { - int32_t data1; - memcpy(&data1, &operand1.values[i].value.sint32_value, 4); - int32_t data2; - memcpy(&data2, &operand1.values[i].value.sint32_value, 4); - if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { - result->values[i].undefined_value = 1; - } - int32_t data = data1/data2; - memcpy(&result->values[i].value.sint32_value, &data, 4); - } - break; - case 64: - { - int64_t data1; - memcpy(&data1, &operand1.values[i].value.sint64_value, 8); - int64_t data2; - memcpy(&data2, &operand1.values[i].value.sint64_value, 8); - if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { - result->values[i].undefined_value = 1; - } - int64_t data = data1 / data2; - memcpy(&result->values[i].value.sint32_value, &data, 8); - } - break; - } - } + #undef SIMPLE_BINARY_OP_32_BIT_HOOK + #define SIMPLE_BINARY_OP_32_BIT_HOOK \ + if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ + result->values[i].undefined_value = 1; \ } - return SPV_REFLECT_RESULT_SUCCESS; + #undef SIMPLE_BINARY_OP_64_BIT_HOOK + #define SIMPLE_BINARY_OP_64_BIT_HOOK \ + if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ + result->values[i].undefined_value = 1; \ + } + DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, /, maxRecursion) + #undef SIMPLE_BINARY_OP_32_BIT_HOOK + #undef SIMPLE_BINARY_OP_64_BIT_HOOK + #define SIMPLE_BINARY_OP_32_BIT_HOOK + #define SIMPLE_BINARY_OP_64_BIT_HOOK case SpvOpUMod: // unsigned modulo // all types must be same unsigned integer scalar or vector type. - { - // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (result->type->traits.numeric.scalar.signedness) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); - SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - if (operand1.type != result->type) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - uint32_t operand_id2; - CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); - SpvReflectValue operand2 = {0}; - res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - if (operand1.type != result->type) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - vec_size = result->type->traits.numeric.vector.component_count; - } - - for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { - result->values[i].undefined_value = 1; - } - switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - { - result->values[i].value.uint32_bool_value = operand1.values[i].value.uint32_bool_value % operand2.values[i].value.uint32_bool_value; - if (operand2.values[i].value.uint32_bool_value == 0) { - result->values[i].undefined_value = 1; - } - } - break; - case 64: - { - result->values[i].value.uint64_value = operand1.values[i].value.uint64_value % operand2.values[i].value.uint64_value; - if (operand2.values[i].value.uint64_value == 0) { - result->values[i].undefined_value = 1; - } - } - break; - } - } - } - return SPV_REFLECT_RESULT_SUCCESS; + DO_UNSIGNED_INTEGER_DIVISION(result, p_module, p_node, %, maxRecursion) case SpvOpSRem: // just the result of % operator. - { - // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); - SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - uint32_t operand_id2; - CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); - SpvReflectValue operand2 = {0}; - res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // component width must be same - if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // vectors must be of same size - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - vec_size = result->type->traits.numeric.vector.component_count; - } - for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { - result->values[i].undefined_value = 1; - } - switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - { - int32_t data1; - memcpy(&data1, &operand1.values[i].value.sint32_value, 4); - int32_t data2; - memcpy(&data2, &operand1.values[i].value.sint32_value, 4); - if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { - result->values[i].undefined_value = 1; - } - int32_t data = data1 % data2; - memcpy(&result->values[i].value.sint32_value, &data, 4); - } - break; - case 64: - { - int64_t data1; - memcpy(&data1, &operand1.values[i].value.sint64_value, 8); - int64_t data2; - memcpy(&data2, &operand1.values[i].value.sint64_value, 8); - if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { - result->values[i].undefined_value = 1; - } - int64_t data = data1 % data2; - memcpy(&result->values[i].value.sint64_value, &data, 8); - } - break; - } - } + #undef SIMPLE_BINARY_OP_32_BIT_HOOK + #define SIMPLE_BINARY_OP_32_BIT_HOOK \ + if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ + result->values[i].undefined_value = 1; \ } - return SPV_REFLECT_RESULT_SUCCESS; + #undef SIMPLE_BINARY_OP_64_BIT_HOOK + #define SIMPLE_BINARY_OP_64_BIT_HOOK \ + if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ + result->values[i].undefined_value = 1; \ + } + DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, %, maxRecursion) + #undef SIMPLE_BINARY_OP_32_BIT_HOOK + #undef SIMPLE_BINARY_OP_64_BIT_HOOK + #define SIMPLE_BINARY_OP_32_BIT_HOOK + #define SIMPLE_BINARY_OP_64_BIT_HOOK case SpvOpSMod: // not result of % operator, need adjusting with dividend... - { - // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); - SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - uint32_t operand_id2; - CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); - SpvReflectValue operand2 = {0}; - res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } + #undef SIMPLE_BINARY_OP_32_BIT_HOOK + #define SIMPLE_BINARY_OP_32_BIT_HOOK \ + if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ + result->values[i].undefined_value = 1; \ + } \ + else if (data != 0) { \ + int sign1 = 0, sign2 = 0; \ + if (data < 0) sign1 = 1; \ + if (data2 < 0) sign2 = 1; \ + /* remainder is not same as modulo here...*/ \ + if ((sign1 + sign2) == 1) { \ + data += data2; \ + } \ + } + #undef SIMPLE_BINARY_OP_64_BIT_HOOK + #define SIMPLE_BINARY_OP_64_BIT_HOOK \ + if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ + result->values[i].undefined_value = 1; \ + } \ + else if (data != 0) { \ + int sign1 = 0, sign2 = 0; \ + if (data < 0) sign1 = 1; \ + if (data2 < 0) sign2 = 1; \ + /* remainder is not same as modulo here...*/ \ + if ((sign1 + sign2) == 1) { \ + data += data2; \ + } \ + } + DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, %, maxRecursion) + #undef SIMPLE_BINARY_OP_32_BIT_HOOK + #undef SIMPLE_BINARY_OP_64_BIT_HOOK + #define SIMPLE_BINARY_OP_32_BIT_HOOK + #define SIMPLE_BINARY_OP_64_BIT_HOOK + case SpvOpShiftRightLogical: + // zero fill right shift. Just >> in c + DO_SHIFT_OPERATION(result, p_module, p_node, >>, maxRecursion) + case SpvOpShiftRightArithmetic: + // fill with sign of original number. + #undef SHIFT_OP_32_BIT_HOOK_PRE + #undef SHIFT_OP_64_BIT_HOOK_PRE + #undef SHIFT_OP_32_BIT_HOOK_POST + #undef SHIFT_OP_64_BIT_HOOK_POST + #define SHIFT_OP_32_BIT_HOOK_PRE uint32_t sign_bit = data & 0x80000000; + #define SHIFT_OP_64_BIT_HOOK_PRE uint64_t sign_bit = data & 0x8000000000000000; + #define SHIFT_OP_32_BIT_HOOK_POST \ + if (sign_bit) { \ + uint32_t fill = 0xffffffff << (32 - shift_num); \ + data |= fill; \ + } + #define SHIFT_OP_64_BIT_HOOK_POST \ + if (sign_bit) { \ + uint64_t fill = 0xffffffffffffffff << (64 - shift_num); \ + data |= fill; \ + } + DO_SHIFT_OPERATION(result, p_module, p_node, >> , maxRecursion) + #undef SHIFT_OP_32_BIT_HOOK_PRE + #undef SHIFT_OP_64_BIT_HOOK_PRE + #undef SHIFT_OP_32_BIT_HOOK_POST + #undef SHIFT_OP_64_BIT_HOOK_POST + #define SHIFT_OP_32_BIT_HOOK_PRE + #define SHIFT_OP_64_BIT_HOOK_PRE + #define SHIFT_OP_32_BIT_HOOK_POST + #define SHIFT_OP_64_BIT_HOOK_POST + case SpvOpShiftLeftLogical: + // zero fill left shift. Just << in c + DO_SHIFT_OPERATION(result, p_module, p_node, << , maxRecursion) + case SpvOpBitwiseOr: + DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, |, maxRecursion) + case SpvOpBitwiseXor: + DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, ^ , maxRecursion) + case SpvOpBitwiseAnd: + DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, & , maxRecursion) - // component width must be same - if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } + // Do not support compostion of vectors for now... + case SpvOpVectorShuffle: + case SpvOpCompositeExtract: + case SpvOpCompositeInsert: + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; - // vectors must be of same size - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - vec_size = result->type->traits.numeric.vector.component_count; - } + case SpvOpLogicalOr: + { - for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { - result->values[i].undefined_value = 1; - } - switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - { - int32_t data1; - memcpy(&data1, &operand1.values[i].value.sint32_value, 4); - int32_t data2; - memcpy(&data2, &operand1.values[i].value.sint32_value, 4); - if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { - result->values[i].undefined_value = 1; - } - int32_t data = data1 % data2; - // multiplying data and data2 may result in overflow... - // need expicit tests... - if (data != 0) { - int sign1 = 0, sign2 = 0; - if (data < 0) sign1 = 1; - if (data2 < 0) sign2 = 1; - // remainder is not same as modulo here... - if ((sign1 + sign2) == 1) { - data += data2; - } - } - memcpy(&result->values[i].value.sint32_value, &data, 4); - } - break; - case 64: - { - int64_t data1; - memcpy(&data1, &operand1.values[i].value.sint64_value, 8); - int64_t data2; - memcpy(&data2, &operand1.values[i].value.sint64_value, 8); - if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { - result->values[i].undefined_value = 1; - } - int64_t data = data1 % data2; - // multiplying data and data2 may result in overflow... - // need expicit tests... - if (data != 0) { - int sign1 = 0, sign2 = 0; - if (data < 0) sign1 = 1; - if (data2 < 0) sign2 = 1; - // remainder is not same as modulo here... - if ((sign1 + sign2) == 1) { - data += data2; - } - } - memcpy(&result->values[i].value.sint64_value, &data, 8); - } - break; - } - } } return SPV_REFLECT_RESULT_SUCCESS; - case SpvOpShiftRightLogical: - // zero fill right shift. Just >> in c - { - // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); - SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - uint32_t operand_id2; - CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); - SpvReflectValue operand2 = {0}; - res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // op1 and result must have same width - if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - uint32_t res_width = result->type->traits.numeric.scalar.width; - - // vectors must be of same size - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - vec_size = result->type->traits.numeric.vector.component_count; - } - - for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { - result->values[i].undefined_value = 1; - } - // load the shift number, set undefined flag if larger than result width - uint8_t shift_num; - switch (operand2.type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - { - uint32_t shift; - memcpy(&shift, &operand2.values[i].value.uint32_bool_value, 4); - if (shift >= res_width) { - result->values[i].undefined_value = 1; - } - shift_num = (uint8_t)shift; - } - break; - case 64: - { - uint64_t shift; - memcpy(&shift, &operand2.values[i].value.uint32_bool_value, 8); - if (shift >= res_width) { - result->values[i].undefined_value = 1; - } - shift_num = (uint8_t)shift; - } - break; - } - switch (res_width) { - default: - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - { - uint32_t data; - memcpy(&data, &operand1.values[i].value.uint32_bool_value, 4); - data >>= shift_num; - memcpy(&result->values[i].value.uint32_bool_value, &data, 4); - } - break; - case 64: - { - uint64_t data; - memcpy(&data, &operand1.values[i].value.uint64_value, 8); - data >>= shift_num; - memcpy(&result->values[i].value.uint64_value, &data, 8); - } - break; - } - } - } - return SPV_REFLECT_RESULT_SUCCESS; - case SpvOpShiftRightArithmetic: - // fill with sign of original number. - { - // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); - SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - uint32_t operand_id2; - CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); - SpvReflectValue operand2 = {0}; - res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // op1 and result must have same width - if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - uint32_t res_width = result->type->traits.numeric.scalar.width; - - // vectors must be of same size - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - vec_size = result->type->traits.numeric.vector.component_count; - } - - for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { - result->values[i].undefined_value = 1; - } - // load the shift number, set undefined flag if larger than result width - uint8_t shift_num; - switch (operand2.type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - { - uint32_t shift; - memcpy(&shift, &operand2.values[i].value.uint32_bool_value, 4); - if (shift >= res_width) { - result->values[i].undefined_value = 1; - } - shift_num = (uint8_t)shift; - } - break; - case 64: - { - uint64_t shift; - memcpy(&shift, &operand2.values[i].value.uint32_bool_value, 8); - if (shift >= res_width) { - result->values[i].undefined_value = 1; - } - shift_num = (uint8_t)shift; - } - break; - } - switch (res_width) { - default: - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - { - uint32_t data; - memcpy(&data, &operand1.values[i].value.uint32_bool_value, 4); - uint32_t sign_bit = data & 0x80000000; - data >>= shift_num; - if (sign_bit) { - uint32_t fill = 0xffffffff << (32 - shift_num); - data |= fill; - } - memcpy(&result->values[i].value.uint32_bool_value, &data, 4); - } - break; - case 64: - { - uint64_t data; - memcpy(&data, &operand1.values[i].value.uint64_value, 8); - uint64_t sign_bit = data & 0x8000000000000000; - data >>= shift_num; - if (sign_bit) { - uint64_t fill = 0xffffffffffffffff << (64 - shift_num); - data |= fill; - } - memcpy(&result->values[i].value.uint64_value, &data, 8); - } - break; - } - } - } - return SPV_REFLECT_RESULT_SUCCESS; - case SpvOpShiftLeftLogical: - { - // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); - SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - uint32_t operand_id2; - CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); - SpvReflectValue operand2 = {0}; - res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // op1 and result must have same width - if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - uint32_t res_width = result->type->traits.numeric.scalar.width; - - // vectors must be of same size - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - vec_size = result->type->traits.numeric.vector.component_count; - } - - for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { - result->values[i].undefined_value = 1; - } - // load the shift number, set undefined flag if larger than result width - uint8_t shift_num; - switch (operand2.type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - { - uint32_t shift; - memcpy(&shift, &operand2.values[i].value.uint32_bool_value, 4); - if (shift >= res_width) { - result->values[i].undefined_value = 1; - } - shift_num = (uint8_t)shift; - } - break; - case 64: - { - uint64_t shift; - memcpy(&shift, &operand2.values[i].value.uint32_bool_value, 8); - if (shift >= res_width) { - result->values[i].undefined_value = 1; - } - shift_num = (uint8_t)shift; - } - break; - } - switch (res_width) { - default: - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - { - uint32_t data; - memcpy(&data, &operand1.values[i].value.uint32_bool_value, 4); - data <<= shift_num; - memcpy(&result->values[i].value.uint32_bool_value, &data, 4); - } - break; - case 64: - { - uint64_t data; - memcpy(&data, &operand1.values[i].value.uint64_value, 8); - data <<= shift_num; - memcpy(&result->values[i].value.uint64_value, &data, 8); - } - break; - } - } - } - return SPV_REFLECT_RESULT_SUCCESS; - case SpvOpBitwiseOr: - { - // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); - SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - // check type here, remember undefined value and booleans with type == null - if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - uint32_t operand_id2; - CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); - SpvReflectValue operand2 = {0}; - res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - // check type here, remember undefined value and booleans with type == null - if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // component width must be same - if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // vectors must be of same size - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - vec_size = result->type->traits.numeric.vector.component_count; - } - - for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { - result->values[i].undefined_value = 1; - } - switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - { - // load data into uint32_t - uint32_t data1; - memcpy(&data1, &operand1.values[i].value.uint32_bool_value, 4); - uint32_t data2; - memcpy(&data2, &operand2.values[i].value.uint32_bool_value, 4); - uint32_t data = data1 | data2; - // write to correct offset - memcpy(&result->values[i].value.uint32_bool_value, &data, 4); - } - break; - case 64: - { - // load data into uint64_t - uint64_t data1; - memcpy(&data1, &operand1.values[i].value.uint64_value, 8); - uint64_t data2; - memcpy(&data2, &operand2.values[i].value.uint64_value, 8); - uint64_t data = data1 | data2; - // write to correct offset - memcpy(&result->values[i].value.uint64_value, &data, 8); - } - break; - } - } - } - return SPV_REFLECT_RESULT_SUCCESS; - case SpvOpBitwiseXor: - { - // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); - SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - // check type here, remember undefined value and booleans with type == null - if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - uint32_t operand_id2; - CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); - SpvReflectValue operand2 = {0}; - res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - // check type here, remember undefined value and booleans with type == null - if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // component width must be same - if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // vectors must be of same size - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - vec_size = result->type->traits.numeric.vector.component_count; - } - - for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { - result->values[i].undefined_value = 1; - } - switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - { - // load data into uint32_t - uint32_t data1; - memcpy(&data1, &operand1.values[i].value.uint32_bool_value, 4); - uint32_t data2; - memcpy(&data2, &operand2.values[i].value.uint32_bool_value, 4); - uint32_t data = data1 ^ data2; - // write to correct offset - memcpy(&result->values[i].value.uint32_bool_value, &data, 4); - } - break; - case 64: - { - // load data into uint64_t - uint64_t data1; - memcpy(&data1, &operand1.values[i].value.uint64_value, 8); - uint64_t data2; - memcpy(&data2, &operand2.values[i].value.uint64_value, 8); - uint64_t data = data1 ^ data2; - // write to correct offset - memcpy(&result->values[i].value.uint64_value, &data, 8); - } - break; - } - } - } - return SPV_REFLECT_RESULT_SUCCESS; - case SpvOpBitwiseAnd: - { - // check result type - if ((result->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // get operand - uint32_t operand_id1; - CHECKED_READU32(p_parser, p_node->word_offset + 4, operand_id1); - SpvReflectValue operand1 = {0}; - res = EvaluateResultImpl(p_module, operand_id1, &operand1, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - // check type here, remember undefined value and booleans with type == null - if (operand1.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - uint32_t operand_id2; - CHECKED_READU32(p_parser, p_node->word_offset + 5, operand_id2); - SpvReflectValue operand2 = {0}; - res = EvaluateResultImpl(p_module, operand_id2, &operand2, maxRecursion - 1); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - // check type here, remember undefined value and booleans with type == null - if (operand2.general_type != SPV_REFLECT_SCALAR_TYPE_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // component width must be same - if (operand1.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.scalar.width != result->type->traits.numeric.scalar.width) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - - // vectors must be of same size - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand1.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type->traits.numeric.vector.component_count != result->type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - vec_size = result->type->traits.numeric.vector.component_count; - } - - for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { - result->values[i].undefined_value = 1; - } - switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case 32: - { - // load data into uint32_t - uint32_t data1; - memcpy(&data1, &operand1.values[i].value.uint32_bool_value, 4); - uint32_t data2; - memcpy(&data2, &operand2.values[i].value.uint32_bool_value, 4); - uint32_t data = data1 & data2; - // write to correct offset - memcpy(&result->values[i].value.uint32_bool_value, &data, 4); - } - break; - case 64: - { - // load data into uint64_t - uint64_t data1; - memcpy(&data1, &operand1.values[i].value.uint64_value, 8); - uint64_t data2; - memcpy(&data2, &operand2.values[i].value.uint64_value, 8); - uint64_t data = data1 & data2; - // write to correct offset - memcpy(&result->values[i].value.uint64_value, &data, 8); - } - break; - } - } - } - return SPV_REFLECT_RESULT_SUCCESS; - case SpvOpVectorShuffle: - - case SpvOpCompositeExtract: - case SpvOpCompositeInsert: - case SpvOpLogicalOr: case SpvOpLogicalAnd: case SpvOpLogicalNot: + case SpvOpLogicalAnd: case SpvOpLogicalNot: case SpvOpLogicalEqual: case SpvOpLogicalNotEqual: case SpvOpSelect: case SpvOpIEqual: case SpvOpINotEqual: case SpvOpULessThan: case SpvOpSLessThan: From cb7b2b9a467409d8d3fe00c44139fd3c8c60cb73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sun, 31 Jul 2022 16:51:25 +0800 Subject: [PATCH 07/44] Most operations done. Operations done, but compositing and de-compositing vectors not included. 16 bit floating point quantization and kernel ops not implemented. --- spirv_reflect.c | 288 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 260 insertions(+), 28 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index ca45fea8..bf307584 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -3394,6 +3394,9 @@ SpvReflectResult GetTypeByTypeId(const SpvReflectShaderModule* p_module, uint32_ #define VECTOR_TYPE_FLAGS (SCALAR_TYPE_FLAGS | SPV_REFLECT_TYPE_FLAG_VECTOR) #define VECTOR_DISALLOWED_FLAGS (~0 ^ VECTOR_TYPE_FLAGS) +#define COMPOSITE_TYPE_FLAGS (VECTOR_TYPE_FLAGS|SPV_REFLECT_TYPE_FLAG_MATRIX|SPV_REFLECT_TYPE_FLAG_STRUCT|SPV_REFLECT_TYPE_FLAG_ARRAY) +#define COMPOSITE_DISALLOWED_FLAGS (~0 ^ COMPOSITE_TYPE_FLAGS) + static SpvReflectScalarType ScalarGeneralTypeFromType(SpvReflectTypeDescription* type) { if ((type->type_flags & SCALAR_TYPE_FLAGS) == SPV_REFLECT_TYPE_FLAG_BOOL) { @@ -5291,8 +5294,7 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint #define CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_result, p_op1) \ { \ - \ - if ((p_result)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + if ((p_result)->type && (p_result)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ if (!((p_op1)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ } \ @@ -5305,8 +5307,8 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint #define CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, p_result, p_op1, p_op2) \ { \ - \ - if ((p_result)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + /* may be scalar boolean if type == null, but never p_result */ \ + if ((p_result)->type && (p_result)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ if (!((p_op1)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ } \ @@ -5343,15 +5345,22 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint #define CHECK_IS_INTEGER_TYPE(p_result) CHECK_IS_BASIC_TYPE_EXCEPT_BOOL(p_result, SPV_REFLECT_TYPE_FLAG_INT) #define CHECK_IS_FLOAT_TYPE(p_result) CHECK_IS_BASIC_TYPE_EXCEPT_BOOL(p_result, SPV_REFLECT_TYPE_FLAG_FLOAT) -#define CHECK_IS_BOOLEAN_TYPE(p_result) \ -{ \ - if((p_result)->type) { \ - if(((p_result)->type->type_flags & SCALAR_TYPE_FLAGS) != b_type) { \ - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - } \ - } \ +#define CHECK_IS_BOOLEAN_TYPE(p_result) \ +{ \ + if((p_result)->type) { \ + if(((p_result)->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_BOOL) { \ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + } \ + } \ } +#define CHECK_VECTOR_OR_SCALAR_TYPE(p_result) \ +{ \ + if ((p_result)->type && ((p_result)->type->type_flags & VECTOR_DISALLOWED_FLAGS)) { \ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + } \ +} \ + #define GET_OPERAND(p_module, p_node, offset, p_operand, maxRecursion) \ { \ uint32_t operand_id; \ @@ -5369,12 +5378,14 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint \ /* check result type */ \ CHECK_IS_INTEGER_TYPE((p_result)) \ + CHECK_VECTOR_OR_SCALAR_TYPE((p_result)) \ \ /* get operand */ \ SpvReflectValue operand1 = {0}; \ GET_OPERAND((simple_op_module), (simple_op_node), 4, &operand1, maxRecursion) \ /* check type here */ \ CHECK_IS_INTEGER_TYPE(&operand1) \ + CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) \ \ /* component width must match. */ \ CHECK_WIDTH_MATCH((p_result), &operand1) \ @@ -5418,15 +5429,18 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ /* check result type*/ \ CHECK_IS_INTEGER_TYPE(p_result) \ + CHECK_VECTOR_OR_SCALAR_TYPE((p_result)) \ \ /* get operand */ \ SpvReflectValue operand1 = {0}; \ GET_OPERAND(simple_op_module, simple_op_node, 4, &operand1, maxRecursion) \ CHECK_IS_INTEGER_TYPE(&operand1) \ + CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) \ \ SpvReflectValue operand2 = {0}; \ GET_OPERAND(simple_op_module, simple_op_node, 5, &operand2, maxRecursion) \ CHECK_IS_INTEGER_TYPE(&operand2) \ + CHECK_VECTOR_OR_SCALAR_TYPE(&operand2) \ \ /* component width must be same */ \ CHECK_WIDTH_MATCH(p_result, &operand1) \ @@ -5476,7 +5490,8 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint { \ CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ /* check result type */ \ - CHECK_IS_INTEGER_TYPE(result) \ + CHECK_IS_INTEGER_TYPE(p_result) \ + CHECK_VECTOR_OR_SCALAR_TYPE(p_result) \ if ((p_result)->type->traits.numeric.scalar.signedness) { \ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ } \ @@ -5484,7 +5499,6 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint /* get operand */ \ SpvReflectValue operand1 = {0}; \ GET_OPERAND(simple_op_module, simple_op_node, 4, &operand1, maxRecursion) \ - \ if (operand1.type != (p_result)->type) { \ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ } \ @@ -5537,15 +5551,18 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint CHECK_INSTRUCTION_SIZE((simple_op_node), 6) \ /* check result type */ \ CHECK_IS_INTEGER_TYPE((p_result)) \ + CHECK_VECTOR_OR_SCALAR_TYPE(p_result) \ \ /* get operand */ \ SpvReflectValue operand1 = {0}; \ GET_OPERAND((simple_op_module), (simple_op_node), 4, &operand1, maxRecursion) \ CHECK_IS_INTEGER_TYPE(&operand1) \ + CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) \ \ SpvReflectValue operand2 = {0}; \ GET_OPERAND((simple_op_module), (simple_op_node), 5, &operand2, maxRecursion) \ CHECK_IS_INTEGER_TYPE(&operand2) \ + CHECK_VECTOR_OR_SCALAR_TYPE(&operand2) \ \ /* op1 and result must have same width */ \ CHECK_WIDTH_MATCH((p_result), &operand1) \ @@ -5607,6 +5624,88 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint return SPV_REFLECT_RESULT_SUCCESS; \ } +#include + +#define DO_BINARY_BOOLEAN_LOGICAL_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion) \ +{ \ + CHECK_INSTRUCTION_SIZE((simple_op_node), 6) \ + \ + /* check result type */ \ + CHECK_IS_BOOLEAN_TYPE((p_result)) \ + CHECK_VECTOR_OR_SCALAR_TYPE((p_result)) \ + \ + /* get operand */ \ + SpvReflectValue operand1 = {0}; \ + GET_OPERAND((simple_op_module), (simple_op_node), 4, &operand1, maxRecursion) \ + CHECK_IS_BOOLEAN_TYPE(&operand1) \ + CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) \ + \ + SpvReflectValue operand2 = {0}; \ + GET_OPERAND((simple_op_module), (simple_op_node), 5, &operand2, maxRecursion) \ + CHECK_IS_BOOLEAN_TYPE(&operand2) \ + CHECK_VECTOR_OR_SCALAR_TYPE(&operand2) \ + \ + /* vectors must be of same size */ \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), &operand1, &operand2) \ + \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1.values[i].undefined_value operation operand2.values[i].undefined_value) { \ + (p_result)->values[i].undefined_value = 1; \ + } \ + /* write to correct offset */ \ + (p_result)->values[i].value.uint32_bool_value \ + = operand1.values[i].value.uint32_bool_value operation operand2.values[i].value.uint32_bool_value; \ + } \ + return SPV_REFLECT_RESULT_SUCCESS; \ +} + +#define DO_BINARY_INTEGER_LOGICAL_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion, _32bit_member, _64bit_member)\ +{ \ + CHECK_INSTRUCTION_SIZE((simple_op_node), 6) \ + \ + /* check result type */ \ + CHECK_IS_BOOLEAN_TYPE((p_result)) \ + CHECK_VECTOR_OR_SCALAR_TYPE((p_result)) \ + \ + /* get operand */ \ + SpvReflectValue operand1 = {0}; \ + GET_OPERAND((simple_op_module), (simple_op_node), 4, &operand1, maxRecursion) \ + CHECK_IS_INTEGER_TYPE(&operand1) \ + CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) \ + \ + SpvReflectValue operand2 = {0}; \ + GET_OPERAND((simple_op_module), (simple_op_node), 5, &operand2, maxRecursion) \ + CHECK_IS_INTEGER_TYPE(&operand2) \ + CHECK_VECTOR_OR_SCALAR_TYPE(&operand2) \ + \ + /* vectors must be of same size */ \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), &operand1, &operand2) \ + \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { \ + (p_result)->values[i].undefined_value = 1; \ + } \ + switch (operand1.type->traits.numeric.scalar.width) { \ + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + case 32: \ + (p_result)->values[i].value.uint32_bool_value \ + = operand1.values[i].value.##_32bit_member operation operand2.values[i].value.##_32bit_member; \ + break; \ + case 64: \ + (p_result)->values[i].value.uint32_bool_value \ + = operand1.values[i].value.##_64bit_member operation operand2.values[i].value.##_64bit_member; \ + break; \ + } \ + } \ + return SPV_REFLECT_RESULT_SUCCESS; \ +} + +#define DO_BINARY_UINTEGER_LOGICAL_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion) \ + DO_BINARY_INTEGER_LOGICAL_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion, uint32_bool_value, uint64_value) +#define DO_BINARY_SINTEGER_LOGICAL_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion) \ + DO_BINARY_INTEGER_LOGICAL_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion, sint32_value, sint64_value) // Used for calculating specialization constants. @@ -5671,9 +5770,7 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint } // only vector and scalar types of int/bool/float types allowed - if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } + CHECK_VECTOR_OR_SCALAR_TYPE(result) result->general_type = ScalarGeneralTypeFromType(result->type); @@ -5687,6 +5784,10 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint // write undefined value to result... { CHECK_INSTRUCTION_SIZE(p_node, 4) + // all types allowed except void + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VOID) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { for (uint32_t i = 0; i < result->type->traits.numeric.vector.component_count; ++i) { result->values[i].undefined_value = 1; @@ -5706,11 +5807,14 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint // check result type CHECK_IS_INTEGER_TYPE(result) + CHECK_VECTOR_OR_SCALAR_TYPE(result) // get operand SpvReflectValue operand1 = {0}; GET_OPERAND(p_module, p_node, 4, &operand1, maxRecursion) CHECK_IS_INTEGER_TYPE(&operand1) + CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) + // operand must be signed if (!operand1.type->traits.numeric.scalar.signedness) { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; @@ -5765,13 +5869,14 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint // check result type CHECK_IS_INTEGER_TYPE(result) + CHECK_VECTOR_OR_SCALAR_TYPE(result) // get operand SpvReflectValue operand1 = {0}; GET_OPERAND(p_module, p_node, 4, &operand1, maxRecursion) - - // check type here, remember undefined value and booleans with type == null CHECK_IS_INTEGER_TYPE(&operand1) + CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) + // operand must not be signed if (operand1.type->traits.numeric.scalar.signedness) { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; @@ -5825,13 +5930,16 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint // check result type CHECK_IS_FLOAT_TYPE(result) - + CHECK_VECTOR_OR_SCALAR_TYPE(result) + // get operand SpvReflectValue operand1 = {0}; GET_OPERAND(p_module, p_node, 4, &operand1, maxRecursion) // check type here, remember undefined value and booleans with type == null CHECK_IS_FLOAT_TYPE(&operand1) + CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) + // vector size must match uint32_t vec_size = 1; CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, result, &operand1) @@ -6032,19 +6140,143 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; case SpvOpLogicalOr: + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(result, p_module, p_node, ||, maxRecursion) + case SpvOpLogicalAnd: + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(result, p_module, p_node, && , maxRecursion) + + case SpvOpLogicalNot: { + CHECK_INSTRUCTION_SIZE(p_node, 5) + /* check result type */ + CHECK_IS_BOOLEAN_TYPE(result) + CHECK_VECTOR_OR_SCALAR_TYPE(result) + + /* get operand */ + SpvReflectValue operand1 = {0}; + GET_OPERAND((p_module), (p_node), 4, &operand1, maxRecursion) + CHECK_IS_BOOLEAN_TYPE(&operand1) + CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) + + /* vectors must be of same size */ + uint32_t vec_size = 1; + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, (result), &operand1) + + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1.values[i].undefined_value) { + (result)->values[i].undefined_value = 1; + } + /* write to correct offset */ + (result)->values[i].value.uint32_bool_value = !operand1.values[i].value.uint32_bool_value; + } } return SPV_REFLECT_RESULT_SUCCESS; - case SpvOpLogicalAnd: case SpvOpLogicalNot: - case SpvOpLogicalEqual: case SpvOpLogicalNotEqual: - case SpvOpSelect: case SpvOpIEqual: case SpvOpINotEqual: - case SpvOpULessThan: case SpvOpSLessThan: - case SpvOpUGreaterThan: case SpvOpSGreaterThan: - case SpvOpULessThanEqual: case SpvOpSLessThanEqual: - case SpvOpUGreaterThanEqual: case SpvOpSGreaterThanEqual: - // add implementations here. - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + + case SpvOpLogicalEqual: + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(result, p_module, p_node, ==, maxRecursion) + case SpvOpLogicalNotEqual: + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(result, p_module, p_node, != , maxRecursion) + case SpvOpSelect: + // same as c/cpp code: a ? b : c; + // should allow composite types if not for spec-constant since 1.4 + { + CHECK_INSTRUCTION_SIZE((p_node), 7) + /* check result type, different from other instance since + it should support composite type if not for spec constant */ + if (result->type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + SpvReflectValue operand1 = {0}; + GET_OPERAND((p_module), (p_node), 4, &operand1, maxRecursion) + CHECK_IS_BOOLEAN_TYPE(&operand1) + CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) + + // cannot skip if type comes with result... + SpvReflectValue operand2 = {0}; + GET_OPERAND((p_module), (p_node), 5, &operand2, maxRecursion) + if (operand2.type != result->type) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + SpvReflectValue operand3 = {0}; + GET_OPERAND((p_module), (p_node), 6, &operand3, maxRecursion) + if (operand3.type != result->type) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + uint32_t vec_size = 1; + // result can be vector if operand is scalar. + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, &operand1, result); + if (vec_size != 1) { + if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + if (operand1.values[i].value.uint32_bool_value) { + if (operand2.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + result->values[i].value = operand2.values[i].value; + } + else { + if (operand3.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + result->values[i].value = operand3.values[i].value; + } + } + } + else { + // deep copy value, inherit undefined value + if (operand1.values[0].undefined_value) { + // we shouldn't care about content here... + for (uint32_t i = 0; i < SPV_REFLECT_MAX_VECTOR_DIMS; ++i) { + result->values[i].undefined_value = 1; + } + } + if (operand1.values[0].value.uint32_bool_value) { + for (uint32_t i = 0; i < SPV_REFLECT_MAX_VECTOR_DIMS; ++i) { + if (operand2.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + result->values[i].value = operand2.values[i].value; + } + } + else { + for (uint32_t i = 0; i < SPV_REFLECT_MAX_VECTOR_DIMS; ++i) { + if (operand3.values[i].undefined_value) { + result->values[i].undefined_value = 1; + } + result->values[i].value = operand3.values[i].value; + } + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; + case SpvOpIEqual: + DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_module, p_node, ==, maxRecursion) + case SpvOpINotEqual: + DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_module, p_node, != , maxRecursion) + case SpvOpULessThan: + DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_module, p_node, < , maxRecursion) + case SpvOpSLessThan: + DO_BINARY_SINTEGER_LOGICAL_OPERATION(result, p_module, p_node, < , maxRecursion) + case SpvOpUGreaterThan: + DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_module, p_node, > , maxRecursion) + case SpvOpSGreaterThan: + DO_BINARY_SINTEGER_LOGICAL_OPERATION(result, p_module, p_node, > , maxRecursion) + case SpvOpULessThanEqual: + DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_module, p_node, <= , maxRecursion) + case SpvOpSLessThanEqual: + DO_BINARY_SINTEGER_LOGICAL_OPERATION(result, p_module, p_node, <= , maxRecursion) + case SpvOpUGreaterThanEqual: + DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_module, p_node, >= , maxRecursion) + case SpvOpSGreaterThanEqual: + DO_BINARY_SINTEGER_LOGICAL_OPERATION(result, p_module, p_node, >= , maxRecursion) // check shader capability... vulkan should assume this... case SpvOpQuantizeToF16: From 4c8a546d4cd3ef1fde394cc7aed8765fb260ae86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sun, 31 Jul 2022 19:50:20 +0800 Subject: [PATCH 08/44] Should now work with vector types and workgroupsize builtin --- common/output_stream.cpp | 94 +++++++++++++++++++++++++++++------ spirv_reflect.c | 105 +++++++++++++++++++++++---------------- spirv_reflect.h | 14 ++++-- 3 files changed, 150 insertions(+), 63 deletions(-) diff --git a/common/output_stream.cpp b/common/output_stream.cpp index f6e61400..4cdf2e91 100644 --- a/common/output_stream.cpp +++ b/common/output_stream.cpp @@ -663,6 +663,13 @@ void ParseBlockMembersToTextLines( // dim = 0 means it's an unbounded array // if (dim > 0) { + if (dim == 0xFFFFFFFF) { + SpvReflectValue val{}; + SpvReflectResult res = obj.EvaluateResult(member.array.spec_constant_op_ids[array_dim_index], val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val.type->traits.numeric.scalar.width == 32)) { + dim = val.values[0].value.uint32_bool_value; + } + } ss_array << "[" << dim << "]"; } else { @@ -702,8 +709,9 @@ void ParseBlockMembersToTextLines( if (dim == 0xFFFFFFFF) { SpvReflectValue val{}; SpvReflectResult res = obj.EvaluateResult(member.array.spec_constant_op_ids[array_dim_index], val); - if (res != SPV_REFLECT_RESULT_SUCCESS) throw; - dim = val.values[0].value.uint32_bool_value; + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val.type->traits.numeric.scalar.width == 32)) { + dim = val.values[0].value.uint32_bool_value; + } } ss_array << "[" << dim << "]"; } @@ -1009,7 +1017,7 @@ void StreamWriteDescriptorBinding(std::ostream& os, const spv_reflect::ShaderMod } } -void StreamWriteInterfaceVariable(std::ostream& os, const SpvReflectInterfaceVariable& obj, const char* indent) +void StreamWriteInterfaceVariable(std::ostream& os, const spv_reflect::ShaderModule& shader, const SpvReflectInterfaceVariable& obj, const char* indent) { const char* t = indent; os << t << "spirv id : " << obj.spirv_id << "\n"; @@ -1028,6 +1036,14 @@ void StreamWriteInterfaceVariable(std::ostream& os, const SpvReflectInterfaceVar if (obj.array.dims_count > 0) { os << t << "array : "; for (uint32_t dim_index = 0; dim_index < obj.array.dims_count; ++dim_index) { + uint32_t dim = obj.array.dims[dim_index]; + if (dim == 0xFFFFFFFF) { + SpvReflectValue val{}; + SpvReflectResult res = shader.EvaluateResult(obj.array.spec_constant_op_ids[dim_index], val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val.type->traits.numeric.scalar.width == 32)) { + dim = val.values[0].value.uint32_bool_value; + } + } os << "[" << obj.array.dims[dim_index] << "]"; } os << "\n"; @@ -1108,28 +1124,74 @@ void StreamWriteSpecializationConstant(std::ostream& os, const SpvReflectSpecial } } -void StreamWriteEntryPoint(std::ostream& os, const SpvReflectEntryPoint& obj, const char* indent) +void StreamWriteEntryPoint(std::ostream& os, const spv_reflect::ShaderModule& shader, const SpvReflectEntryPoint& obj, const char* indent) { os << indent << "entry point : " << obj.name; os << " (stage=" << ToStringShaderStage(obj.shader_stage) << ")"; if (obj.shader_stage == SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT) { os << "\n"; - os << "local size : " << "(" << obj.local_size.x << ", " << obj.local_size.y << ", " << obj.local_size.z << ")"; + if (obj.local_size.flags & 2) { + os << "local size : "; + } + else { + os << "local size hint : "; + } + if(obj.local_size.flags & 4) { + SpvReflectValue val{}; + SpvReflectResult res = shader.EvaluateResult(obj.local_size.x, val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == (SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_VECTOR)) + && (val.type->traits.numeric.scalar.width == 32)) { + os << "(" << val.values[0].value.uint32_bool_value << ", " << val.values[1].value.uint32_bool_value << ", " << val.values[2].value.uint32_bool_value << ")"; + } + else { + os << "(failed evaluation of WorkGroupSize Builtin)"; + } + } + else if(obj.local_size.flags & 1) { + os << "("; + SpvReflectValue val = {0}; + SpvReflectResult res = shader.EvaluateResult(obj.local_size.x, val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val.type->traits.numeric.scalar.width == 32)) { + os << val.values[0].value.uint32_bool_value; + } + else { + os << "unknown"; + } + os << ", "; + res = shader.EvaluateResult(obj.local_size.y, val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val.type->traits.numeric.scalar.width == 32)) { + os << val.values[0].value.uint32_bool_value; + } + else { + os << "unknown"; + } os << ", "; + res = shader.EvaluateResult(obj.local_size.z, val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val.type->traits.numeric.scalar.width == 32)) { + os << val.values[0].value.uint32_bool_value; + } + else { + os << "unknown"; + } + os << ")"; + } + else{ + os << "(" << obj.local_size.x << ", " << obj.local_size.y << ", " << obj.local_size.z << ")"; + } } } -void StreamWriteShaderModule(std::ostream& os, const SpvReflectShaderModule& obj, const char* indent) +void StreamWriteShaderModule(std::ostream& os, const spv_reflect::ShaderModule& obj, const char* indent) { (void)indent; - os << "generator : " << ToStringGenerator(obj.generator) << "\n"; - os << "source lang : " << spvReflectSourceLanguage(obj.source_language) << "\n"; - os << "source lang ver : " << obj.source_language_version << "\n"; - os << "source file : " << (obj.source_file != NULL ? obj.source_file : "") << "\n"; + os << "generator : " << ToStringGenerator(obj.GetShaderModule().generator) << "\n"; + os << "source lang : " << spvReflectSourceLanguage(obj.GetShaderModule().source_language) << "\n"; + os << "source lang ver : " << obj.GetShaderModule().source_language_version << "\n"; + os << "source file : " << (obj.GetShaderModule().source_file != NULL ? obj.GetShaderModule().source_file : "") << "\n"; //os << "shader stage : " << ToStringShaderStage(obj.shader_stage) << "\n"; - for (uint32_t i = 0; i < obj.entry_point_count; ++i) { - StreamWriteEntryPoint(os, obj.entry_points[i], ""); - if (i < (obj.entry_point_count - 1)) { + for (uint32_t i = 0; i < obj.GetShaderModule().entry_point_count; ++i) { + StreamWriteEntryPoint(os, obj, obj.GetShaderModule().entry_points[i], ""); + if (i < (obj.GetShaderModule().entry_point_count - 1)) { os << "\n"; } } @@ -1149,7 +1211,7 @@ void WriteReflection(const spv_reflect::ShaderModule& obj, bool flatten_cbuffers const char* tt = " "; const char* ttt = " "; - StreamWriteShaderModule(os, obj.GetShaderModule(), ""); + StreamWriteShaderModule(os, obj, ""); uint32_t count = 0; std::vector variables; @@ -1195,7 +1257,7 @@ void WriteReflection(const spv_reflect::ShaderModule& obj, bool flatten_cbuffers auto p_var = variables[i]; USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); os << tt << i << ":" << "\n"; - StreamWriteInterfaceVariable(os, *p_var, ttt); + StreamWriteInterfaceVariable(os, obj,*p_var, ttt); if (i < (count - 1)) { os << "\n"; } @@ -1217,7 +1279,7 @@ void WriteReflection(const spv_reflect::ShaderModule& obj, bool flatten_cbuffers auto p_var = variables[i]; USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); os << tt << i << ":" << "\n"; - StreamWriteInterfaceVariable(os, *p_var, ttt); + StreamWriteInterfaceVariable(os, obj, *p_var, ttt); if (i < (count - 1)) { os << "\n"; } diff --git a/spirv_reflect.c b/spirv_reflect.c index bf307584..5cfd6027 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -1445,6 +1445,7 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser) case SpvDecorationBuiltIn: { p_target_decorations->is_built_in = true; uint32_t word_offset = p_node->word_offset + member_offset + 3; + // no rule specifies a result cannot be decorated twice. But let's assume this for now... CHECKED_READU32_CAST(p_parser, word_offset, SpvBuiltIn, p_target_decorations->built_in); } break; @@ -3397,34 +3398,16 @@ SpvReflectResult GetTypeByTypeId(const SpvReflectShaderModule* p_module, uint32_ #define COMPOSITE_TYPE_FLAGS (VECTOR_TYPE_FLAGS|SPV_REFLECT_TYPE_FLAG_MATRIX|SPV_REFLECT_TYPE_FLAG_STRUCT|SPV_REFLECT_TYPE_FLAG_ARRAY) #define COMPOSITE_DISALLOWED_FLAGS (~0 ^ COMPOSITE_TYPE_FLAGS) -static SpvReflectScalarType ScalarGeneralTypeFromType(SpvReflectTypeDescription* type) -{ - if ((type->type_flags & SCALAR_TYPE_FLAGS) == SPV_REFLECT_TYPE_FLAG_BOOL) { - return SPV_REFLECT_SCALAR_TYPE_BOOL; - } - else if ((type->type_flags & SCALAR_TYPE_FLAGS) == SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_SCALAR_TYPE_INT; - } - else if ((type->type_flags & SCALAR_TYPE_FLAGS) == SPV_REFLECT_TYPE_FLAG_FLOAT) { - return SPV_REFLECT_SCALAR_TYPE_FLOAT; - } - else { - return SPV_REFLECT_SCALAR_TYPE_UNKNOWN; - } -} - static SpvReflectResult GetScalarConstant(const SpvReflectShaderModule* p_module, SpvReflectPrvNode* p_node, - SpvReflectScalarValue* result, SpvReflectScalarType* general_type, SpvReflectTypeDescription** type) + SpvReflectScalarValue* result, SpvReflectTypeDescription** type) { SpvReflectPrvParser* p_parser = p_module->_internal->parser; - SpvReflectScalarType g_type; SpvReflectTypeDescription* d_type; SpvReflectResult res = GetTypeByTypeId(p_module, p_node->result_type_id, &d_type); if (res != SPV_REFLECT_RESULT_SUCCESS) return res; if(d_type->type_flags & SCALAR_DISALLOWED_FLAGS) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - g_type = ScalarGeneralTypeFromType(d_type); uint32_t low_word; CHECKED_READU32(p_parser, p_node->word_offset + 3, low_word); // There is no alignment requirements in c/cpp for unions @@ -3440,7 +3423,6 @@ static SpvReflectResult GetScalarConstant(const SpvReflectShaderModule* p_module else { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } - *general_type = g_type; *type = d_type; return SPV_REFLECT_RESULT_SUCCESS; } @@ -3466,6 +3448,18 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars for (size_t i = 0; i < p_parser->node_count; ++i) { SpvReflectPrvNode* p_node = &(p_parser->nodes[i]); + // check first if it's WorkGroupSize builtin + // maybe handling builtin as global map may be better. + if (p_node->decorations.built_in == SpvBuiltInWorkgroupSize) { + // WorkGroupSize builtin's target is all ExecutionMode instructions. + for(uint32_t j = 0; jentry_point_count; ++j) { + if(p_module->entry_points[j].spirv_execution_model == SpvExecutionModelKernel|| + p_module->entry_points[j].spirv_execution_model == SpvExecutionModelGLCompute){ + p_module->entry_points[j].local_size.flags = 4; + p_module->entry_points[j].local_size.x = p_node->result_id; + } + } + } // Specconstants with no id means constant switch(p_node->op) { default: continue; @@ -3482,7 +3476,7 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars case SpvOpSpecConstant: { SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS; SpvReflectScalarValue default_value = { 0 }; - result = GetScalarConstant(p_module, p_node, &default_value, &p_module->specialization_constants[index].general_type, &p_module->specialization_constants[index].type); + result = GetScalarConstant(p_module, p_node, &default_value, &p_module->specialization_constants[index].type); if (result != SPV_REFLECT_RESULT_SUCCESS) return result; p_module->specialization_constants[index].default_value = default_value; p_module->specialization_constants[index].current_value = p_module->specialization_constants[index].default_value; @@ -3490,11 +3484,11 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars } // spec constant id cannot be the same, at least for valid values. (invalid value is just constant?) if (p_node->decorations.specialization_constant.value != (uint32_t)INVALID_VALUE) { - for (uint32_t j = 0; j < index; ++j) { - if (p_module->specialization_constants[j].constant_id == p_node->decorations.specialization_constant.value) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_DUPLICATE_SPEC_CONSTANT_NAME; - } + for (uint32_t j = 0; j < index; ++j) { + if (p_module->specialization_constants[j].constant_id == p_node->decorations.specialization_constant.value) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_DUPLICATE_SPEC_CONSTANT_NAME; } + } } p_module->specialization_constants[index].name = p_node->name; @@ -3895,10 +3889,6 @@ static SpvReflectResult CreateShaderModule( result = ParsePushConstantBlocks(parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } - if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseSpecializationConstants(parser, p_module); - SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); - } if (result == SPV_REFLECT_RESULT_SUCCESS) { result = ParseEntryPoints(parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); @@ -3928,6 +3918,11 @@ static SpvReflectResult CreateShaderModule( result = ParseExecutionModes(parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } + // WorkGroupSize builtin needs to update entry point localsize member + if (result == SPV_REFLECT_RESULT_SUCCESS) { + result = ParseSpecializationConstants(parser, p_module); + SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); + } // Destroy module if parse was not successful if (result != SPV_REFLECT_RESULT_SUCCESS) { @@ -5723,22 +5718,20 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint if (!p_node) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; switch (p_node->op) { default: - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; case SpvOpConstantTrue: { - result->general_type = SPV_REFLECT_SCALAR_TYPE_BOOL; result->values[0].value.uint32_bool_value = 1; } return SPV_REFLECT_RESULT_SUCCESS; case SpvOpConstantFalse: { - result->general_type = SPV_REFLECT_SCALAR_TYPE_BOOL; result->values[0].value.uint32_bool_value = 0; } return SPV_REFLECT_RESULT_SUCCESS; case SpvOpConstant: CONSTANT_RESULT: - return GetScalarConstant(p_module, p_node, &result->values[0], &result->general_type, &result->type); + return GetScalarConstant(p_module, p_node, &result->values[0], &result->type); case SpvOpSpecConstantTrue: case SpvOpSpecConstantFalse: case SpvOpSpecConstant: { @@ -5748,32 +5741,58 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint SpvReflectSpecializationConstant* p_constant; res = GetSpecContantById(p_module, p_node->decorations.specialization_constant.value, &p_constant); if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - result->general_type = p_constant->general_type; result->type = p_constant->type; result->values[0] = p_constant->current_value; } return SPV_REFLECT_RESULT_SUCCESS; case SpvOpSpecConstantComposite: { - // only support scalar types for now... + // only support compositing vector types for now... + // vectors are needed for spv compiled to WorkgroupSize builtin + // in expressing actual localsize + res = GetTypeByTypeId(p_module, p_node->result_type_id, &result->type); + if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + // compositing types + if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + } + uint32_t vec_size = 1; + // should always have, since scalars do not need composite + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + vec_size = result->type->traits.numeric.vector.component_count; + } + // check instruction size + if (p_node->word_count != 3 + vec_size) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + } + for (uint32_t i = 0; i < vec_size; ++i) { + SpvReflectValue operandi = {0}; + GET_OPERAND(p_module, p_node, 3 + i, &operandi, maxRecursion); + // check type compatibility + if (operandi.type && (operandi.type->type_flags & SCALAR_DISALLOWED_FLAGS)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if ((!operandi.type && !(result->type->type_flags& SPV_REFLECT_TYPE_FLAG_BOOL)) + ||(operandi.type && ((operandi.type->type_flags & SCALAR_TYPE_FLAGS) != (result->type->type_flags & SCALAR_TYPE_FLAGS)))) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + result->values[i] = operandi.values[0]; + } } - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + return SPV_REFLECT_RESULT_SUCCESS; case SpvOpSpecConstantOp: { // operation has result type id, thus must be typed res = GetTypeByTypeId(p_module, p_node->result_type_id, &result->type); if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - // no support for vectors yet... - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + // only vector and scalar types of int/bool/float types implemented + // only OpSelect, OpUndef and access chain instructions can work with non-vector or scalar types + // they are not currently supported... (likely never will) + if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; } - // only vector and scalar types of int/bool/float types allowed - CHECK_VECTOR_OR_SCALAR_TYPE(result) - - result->general_type = ScalarGeneralTypeFromType(result->type); - // evaluate op uint32_t spec_op; CHECKED_READU32(p_parser, p_node->word_offset + 3, spec_op); diff --git a/spirv_reflect.h b/spirv_reflect.h index f9b4d862..3efb8722 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -356,13 +356,19 @@ typedef uint16_t spv_reflect_float16_t; typedef struct SpvReflectScalarValue { // strongly typed for evaluation purpose union { + /* small types not implemented yet... */ + uint8_t uint8_value; + int8_t sint8_value; + uint16_t uint16_value; + int16_t sint16_value; spv_reflect_float16_t float16_value; - float float32_value; - double float64_value; + /* types that are currently supported */ uint32_t uint32_bool_value; - uint64_t uint64_value; int32_t sint32_value; + float float32_value; + uint64_t uint64_value; int64_t sint64_value; + double float64_value; } value; // for use with OpUndef int undefined_value; @@ -370,7 +376,6 @@ typedef struct SpvReflectScalarValue { // only scalar, vector types can evaluate values for now... typedef struct SpvReflectValue { - SpvReflectScalarType general_type; // may be null if boolean, coming from OpSpecConstantTrue/OpSpecConstantFalse // but type found through return type id is never null. SpvReflectTypeDescription* type; @@ -514,6 +519,7 @@ typedef struct SpvReflectEntryPoint { int flags; // 0 if just fixed local size // 1 bit set if is instruction id of spec constant // 2 bit set if is hint (kernel mode not supported in vulkan, though) + // 4 bit is set if x is result_id decorated with WorkGroupSize // this change may break abi // if using specialization constants, // xyz refers to evaluated result, not just constant_id From f3a72fca25d216c46c178000cb2c4a8f378c014d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Mon, 1 Aug 2022 01:49:15 +0800 Subject: [PATCH 09/44] Compositing and de-compositing vectors implemented --- common/output_stream.cpp | 34 ++- spirv_reflect.c | 611 +++++++++++++++++++++++++-------------- spirv_reflect.h | 43 +-- 3 files changed, 447 insertions(+), 241 deletions(-) diff --git a/common/output_stream.cpp b/common/output_stream.cpp index 4cdf2e91..92dfeaf4 100644 --- a/common/output_stream.cpp +++ b/common/output_stream.cpp @@ -667,7 +667,7 @@ void ParseBlockMembersToTextLines( SpvReflectValue val{}; SpvReflectResult res = obj.EvaluateResult(member.array.spec_constant_op_ids[array_dim_index], val); if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val.type->traits.numeric.scalar.width == 32)) { - dim = val.values[0].value.uint32_bool_value; + dim = val.data.numeric.scalar.value.uint32_bool_value; } } ss_array << "[" << dim << "]"; @@ -710,7 +710,7 @@ void ParseBlockMembersToTextLines( SpvReflectValue val{}; SpvReflectResult res = obj.EvaluateResult(member.array.spec_constant_op_ids[array_dim_index], val); if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val.type->traits.numeric.scalar.width == 32)) { - dim = val.values[0].value.uint32_bool_value; + dim = val.data.numeric.scalar.value.uint32_bool_value; } } ss_array << "[" << dim << "]"; @@ -1041,7 +1041,7 @@ void StreamWriteInterfaceVariable(std::ostream& os, const spv_reflect::ShaderMod SpvReflectValue val{}; SpvReflectResult res = shader.EvaluateResult(obj.array.spec_constant_op_ids[dim_index], val); if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val.type->traits.numeric.scalar.width == 32)) { - dim = val.values[0].value.uint32_bool_value; + dim = val.data.numeric.scalar.value.uint32_bool_value; } } os << "[" << obj.array.dims[dim_index] << "]"; @@ -1071,12 +1071,22 @@ void StreamWriteSpecializationConstant(std::ostream& os, const SpvReflectSpecial os << t << "constant id: " << obj.constant_id << "\n"; os << t << "name : " << (obj.name != NULL ? obj.name : "") << '\n'; os << t << "type : "; - switch (obj.general_type) { - case SPV_REFLECT_SCALAR_TYPE_BOOL: + int type = 0; + if (!obj.type || obj.type->type_flags == SPV_REFLECT_TYPE_FLAG_BOOL) { + type = 1; + } + else if (obj.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) { + type = 2; + } + else if (obj.type->type_flags == SPV_REFLECT_TYPE_FLAG_FLOAT) { + type = 3; + } + switch (type) { + case 1: os << "boolean\n"; os << t << "default : " << obj.default_value.value.uint32_bool_value; break; - case SPV_REFLECT_SCALAR_TYPE_INT: + case 2: if (obj.type->traits.numeric.scalar.signedness) { os << "signed "; } @@ -1106,7 +1116,7 @@ void StreamWriteSpecializationConstant(std::ostream& os, const SpvReflectSpecial os << "default value not native in c/cpp"; } break; - case SPV_REFLECT_SCALAR_TYPE_FLOAT: + case 3: os << obj.type->traits.numeric.scalar.width << " bit floating point\n"; os << t << "default : "; if (obj.type->traits.numeric.scalar.width == 32) { @@ -1141,7 +1151,9 @@ void StreamWriteEntryPoint(std::ostream& os, const spv_reflect::ShaderModule& sh SpvReflectResult res = shader.EvaluateResult(obj.local_size.x, val); if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == (SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_VECTOR)) && (val.type->traits.numeric.scalar.width == 32)) { - os << "(" << val.values[0].value.uint32_bool_value << ", " << val.values[1].value.uint32_bool_value << ", " << val.values[2].value.uint32_bool_value << ")"; + os << "(" << val.data.numeric.vector.value[0].value.uint32_bool_value << ", " + << val.data.numeric.vector.value[1].value.uint32_bool_value << ", " + << val.data.numeric.vector.value[2].value.uint32_bool_value << ")"; } else { os << "(failed evaluation of WorkGroupSize Builtin)"; @@ -1152,7 +1164,7 @@ void StreamWriteEntryPoint(std::ostream& os, const spv_reflect::ShaderModule& sh SpvReflectValue val = {0}; SpvReflectResult res = shader.EvaluateResult(obj.local_size.x, val); if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val.type->traits.numeric.scalar.width == 32)) { - os << val.values[0].value.uint32_bool_value; + os << val.data.numeric.scalar.value.uint32_bool_value; } else { os << "unknown"; @@ -1160,14 +1172,14 @@ void StreamWriteEntryPoint(std::ostream& os, const spv_reflect::ShaderModule& sh os << ", "; res = shader.EvaluateResult(obj.local_size.y, val); if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val.type->traits.numeric.scalar.width == 32)) { - os << val.values[0].value.uint32_bool_value; + os << val.data.numeric.scalar.value.uint32_bool_value; } else { os << "unknown"; } os << ", "; res = shader.EvaluateResult(obj.local_size.z, val); if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val.type->traits.numeric.scalar.width == 32)) { - os << val.values[0].value.uint32_bool_value; + os << val.data.numeric.vector.value[2].value.uint32_bool_value; } else { os << "unknown"; diff --git a/spirv_reflect.c b/spirv_reflect.c index 5cfd6027..0ba3deb1 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -522,7 +522,7 @@ static SpvReflectPrvNode* FindNode( return p_node; } -static SpvReflectTypeDescription* FindType(SpvReflectShaderModule* p_module, uint32_t type_id) +static SpvReflectTypeDescription* FindType(const SpvReflectShaderModule* p_module, uint32_t type_id) { SpvReflectTypeDescription* p_type = NULL; for (size_t i = 0; i < p_module->_internal->type_description_count; ++i) { @@ -1621,6 +1621,9 @@ static SpvReflectResult ParseType( uint32_t component_type_id = (uint32_t)INVALID_VALUE; IF_READU32(result, p_parser, p_node->word_offset + 2, component_type_id); IF_READU32(result, p_parser, p_node->word_offset + 3, p_type->traits.numeric.vector.component_count); + + p_type->component_type_id = component_type_id; + // Parse component type SpvReflectPrvNode* p_next_node = FindNode(p_parser, component_type_id); if (IsNotNull(p_next_node)) { @@ -1638,6 +1641,9 @@ static SpvReflectResult ParseType( uint32_t column_type_id = (uint32_t)INVALID_VALUE; IF_READU32(result, p_parser, p_node->word_offset + 2, column_type_id); IF_READU32(result, p_parser, p_node->word_offset + 3, p_type->traits.numeric.matrix.column_count); + + p_type->component_type_id = column_type_id; + SpvReflectPrvNode* p_next_node = FindNode(p_parser, column_type_id); if (IsNotNull(p_next_node)) { result = ParseType(p_parser, p_next_node, NULL, p_module, p_type); @@ -1702,6 +1708,9 @@ static SpvReflectResult ParseType( uint32_t length_id = (uint32_t)INVALID_VALUE; IF_READU32(result, p_parser, p_node->word_offset + 2, element_type_id); IF_READU32(result, p_parser, p_node->word_offset + 3, length_id); + + p_type->component_type_id = element_type_id; + // NOTE: Array stride is decorated using OpDecorate instead of // OpMemberDecorate, even if the array is apart of a struct. p_type->traits.array.stride = p_node->decorations.array_stride; @@ -3378,18 +3387,6 @@ static SpvReflectResult ParseExecutionModes( return SPV_REFLECT_RESULT_SUCCESS; } -SpvReflectResult GetTypeByTypeId(const SpvReflectShaderModule* p_module, uint32_t type_id, SpvReflectTypeDescription** pp_type) -{ - SpvReflectResult res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; - for (uint32_t i = 0; i < p_module->_internal->type_description_count; ++i) { - if (p_module->_internal->type_descriptions[i].id == type_id) { - *pp_type = &p_module->_internal->type_descriptions[i]; - return SPV_REFLECT_RESULT_SUCCESS; - } - } - return res; -} - #define SCALAR_TYPE_FLAGS (SPV_REFLECT_TYPE_FLAG_BOOL | SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_FLOAT) #define SCALAR_DISALLOWED_FLAGS (~0 ^ SCALAR_TYPE_FLAGS) #define VECTOR_TYPE_FLAGS (SCALAR_TYPE_FLAGS | SPV_REFLECT_TYPE_FLAG_VECTOR) @@ -3399,13 +3396,12 @@ SpvReflectResult GetTypeByTypeId(const SpvReflectShaderModule* p_module, uint32_ #define COMPOSITE_DISALLOWED_FLAGS (~0 ^ COMPOSITE_TYPE_FLAGS) static SpvReflectResult GetScalarConstant(const SpvReflectShaderModule* p_module, SpvReflectPrvNode* p_node, - SpvReflectScalarValue* result, SpvReflectTypeDescription** type) + SpvReflectScalarValueData* result, SpvReflectTypeDescription** type) { SpvReflectPrvParser* p_parser = p_module->_internal->parser; - SpvReflectTypeDescription* d_type; - SpvReflectResult res = GetTypeByTypeId(p_module, p_node->result_type_id, &d_type); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + SpvReflectTypeDescription* d_type = FindType(p_module, p_node->result_type_id); + if (!d_type) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; if(d_type->type_flags & SCALAR_DISALLOWED_FLAGS) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; uint32_t low_word; @@ -3464,18 +3460,16 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars switch(p_node->op) { default: continue; case SpvOpSpecConstantTrue: { - p_module->specialization_constants[index].general_type = SPV_REFLECT_SCALAR_TYPE_BOOL; p_module->specialization_constants[index].default_value.value.uint32_bool_value = 1; p_module->specialization_constants[index].current_value = p_module->specialization_constants[index].default_value; } break; case SpvOpSpecConstantFalse: { - p_module->specialization_constants[index].general_type = SPV_REFLECT_SCALAR_TYPE_BOOL; p_module->specialization_constants[index].default_value.value.uint32_bool_value = 0; p_module->specialization_constants[index].current_value = p_module->specialization_constants[index].default_value; } break; case SpvOpSpecConstant: { SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS; - SpvReflectScalarValue default_value = { 0 }; + SpvReflectScalarValueData default_value = { 0 }; result = GetScalarConstant(p_module, p_node, &default_value, &p_module->specialization_constants[index].type); if (result != SPV_REFLECT_RESULT_SUCCESS) return result; p_module->specialization_constants[index].default_value = default_value; @@ -5278,7 +5272,50 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint return res; } -#include +SpvReflectResult GetMemberByIndex(const SpvReflectShaderModule* p_module, const SpvReflectValueData* mother, const SpvReflectTypeDescription* mother_type, + uint32_t index, SpvReflectValueData** result, const SpvReflectTypeDescription** child_type) +{ + if (!mother_type || !(mother_type->type_flags & VECTOR_DISALLOWED_FLAGS)) { + if (!mother_type || !(mother_type->type_flags & SCALAR_DISALLOWED_FLAGS)) { + // scalar types have no composition + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + else { + // mother is a simple vector + SpvReflectTypeDescription* c_type = FindType(p_module, mother_type->component_type_id); + if (!c_type) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; + } + if (index > mother_type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + } + *child_type = c_type; + *result = (SpvReflectValueData*)&mother->numeric.vector.value[index]; + return SPV_REFLECT_RESULT_SUCCESS; + } + } + else { + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + } +} + +SpvReflectResult CopyValueData(const SpvReflectShaderModule* p_module, const SpvReflectTypeDescription* type, SpvReflectValueData* dst, SpvReflectValueData* src) +{ + if (!type || !(type->type_flags & VECTOR_DISALLOWED_FLAGS)) { + if (!type || !(type->type_flags & SCALAR_DISALLOWED_FLAGS)) { + dst->numeric.scalar = src->numeric.scalar; + // scalar types have no composition + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + else { + dst->numeric.vector = src->numeric.vector; + return SPV_REFLECT_RESULT_SUCCESS; + } + } + else { + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + } +} #define CHECK_INSTRUCTION_SIZE(node, expected) \ { \ @@ -5300,10 +5337,13 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint } \ } -#define CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, p_result, p_op1, p_op2) \ +#define CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, p_result, p_op1, p_op2)\ { \ /* may be scalar boolean if type == null, but never p_result */ \ if ((p_result)->type && (p_result)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + if(!(p_op1)->type || !(p_op2)->type) { \ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + } \ if (!((p_op1)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ } \ @@ -5387,27 +5427,28 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint \ /* vector size must match */ \ uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, (p_result), &operand1) \ + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, (p_result), &operand1)\ \ /* now do the job */ \ for (uint32_t i = 0; i < vec_size; ++i) { \ - (p_result)->values[i].undefined_value = operand1.values->undefined_value; \ + (p_result)->data.numeric.vector.value[i].undefined_value \ + = operand1.data.numeric.vector.value[i].undefined_value; \ switch (operand1.type->traits.numeric.scalar.width) { \ default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ case 32: \ /* 32 bit integer */ \ { \ - int32_t data = operand1.values[i].value.sint32_value; \ + int32_t data = operand1.data.numeric.vector.value[i].value.sint32_value; \ SIMPLE_UNARY_OP_32_BIT_HOOK \ - (p_result)->values[i].value.sint32_value = data; \ + (p_result)->data.numeric.vector.value[i].value.sint32_value = data; \ } \ break; \ case 64: \ /* 64 bit integer */ \ { \ - int64_t data = operand1.values[i].value.sint64_value; \ + int64_t data = operand1.data.numeric.vector.value[i].value.sint64_value; \ SIMPLE_UNARY_OP_64_BIT_HOOK \ - (p_result)->values[i].value.sint64_value = data; \ + (p_result)->data.numeric.vector.value[i].value.sint64_value = data; \ } \ break; \ } \ @@ -5443,36 +5484,37 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint \ /* vectors must be of same size */ \ uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, p_result, &operand1, &operand2) \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), &operand1, &operand2) \ /* now do the job, width unknown but same, all three sign unkown \ but still, since spv defines signed integer as 2-compliment, \ so do recent c/cpp standard, directly adding uint should be enough.*/ \ for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { \ - (p_result)->values[i].undefined_value = 1; \ + if (operand1.data.numeric.vector.value[i].undefined_value \ + || operand2.data.numeric.vector.value[i].undefined_value) { \ + (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ } \ switch ((p_result)->type->traits.numeric.scalar.width) { \ default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ case 32: \ { \ /* load data into int32_t*/ \ - int32_t data1 = operand1.values[i].value.sint32_value; \ - int32_t data2 = operand2.values[i].value.sint32_value; \ + int32_t data1 = operand1.data.numeric.vector.value[i].value.sint32_value; \ + int32_t data2 = operand2.data.numeric.vector.value[i].value.sint32_value; \ int32_t data = data1 operation data2; \ SIMPLE_BINARY_OP_32_BIT_HOOK \ /* write to correct offset */ \ - (p_result)->values[i].value.sint32_value = data; \ + (p_result)->data.numeric.vector.value[i].value.sint32_value = data; \ } \ break; \ case 64: \ { \ /* load data into int64_t*/ \ - int64_t data1 = operand1.values[i].value.sint64_value; \ - int64_t data2 = operand2.values[i].value.sint64_value; \ + int64_t data1 = operand1.data.numeric.vector.value[i].value.sint64_value; \ + int64_t data2 = operand2.data.numeric.vector.value[i].value.sint64_value; \ int64_t data = data1 operation data2; \ SIMPLE_BINARY_OP_32_BIT_HOOK \ /* write to correct offset */ \ - (p_result)->values[i].value.sint64_value = data; \ + (p_result)->data.numeric.vector.value[i].value.sint64_value = data; \ } \ break; \ } \ @@ -5494,40 +5536,41 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint /* get operand */ \ SpvReflectValue operand1 = {0}; \ GET_OPERAND(simple_op_module, simple_op_node, 4, &operand1, maxRecursion) \ - if (operand1.type != (p_result)->type) { \ + if ((!operand1.type) || operand1.type->id != (p_result)->type->id) { \ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ } \ SpvReflectValue operand2 = {0}; \ GET_OPERAND(simple_op_module, simple_op_node, 5, &operand2, maxRecursion) \ - if (operand1.type != (p_result)->type) { \ + if ((!operand2.type) || operand2.type->id != (p_result)->type->id) { \ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ } \ \ uint32_t vec_size = 1; \ - if ((p_result)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ - vec_size = result->type->traits.numeric.vector.component_count; \ - } \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), &operand1, &operand2) \ for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { \ - (p_result)->values[i].undefined_value = 1; \ + if (operand1.data.numeric.vector.value[i].undefined_value \ + || operand2.data.numeric.vector.value[i].undefined_value) { \ + (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ } \ switch ((p_result)->type->traits.numeric.scalar.width) { \ default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ case 32: \ { \ - (p_result)->values[i].value.uint32_bool_value \ - = operand1.values[i].value.uint32_bool_value operation operand2.values[i].value.uint32_bool_value; \ - if (operand2.values[i].value.uint32_bool_value == 0) { \ - (p_result)->values[i].undefined_value = 1; \ + (p_result)->data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1.data.numeric.vector.value[i].value.uint32_bool_value \ + operation operand2.data.numeric.vector.value[i].value.uint32_bool_value; \ + if (operand2.data.numeric.vector.value[i].value.uint32_bool_value == 0) { \ + (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ } \ } \ break; \ case 64: \ { \ - (p_result)->values[i].value.uint64_value \ - = operand1.values[i].value.uint64_value operation operand2.values[i].value.uint64_value; \ - if (operand2.values[i].value.uint64_value == 0) { \ - (p_result)->values[i].undefined_value = 1; \ + (p_result)->data.numeric.vector.value[i].value.uint64_value \ + = operand1.data.numeric.vector.value[i].value.uint64_value \ + operation operand2.data.numeric.vector.value[i].value.uint64_value; \ + if (operand2.data.numeric.vector.value[i].value.uint64_value == 0) { \ + (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ } \ } \ break; \ @@ -5541,86 +5584,85 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint #define SHIFT_OP_32_BIT_HOOK_POST #define SHIFT_OP_64_BIT_HOOK_POST -#define DO_SHIFT_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion) \ -{ \ - CHECK_INSTRUCTION_SIZE((simple_op_node), 6) \ - /* check result type */ \ - CHECK_IS_INTEGER_TYPE((p_result)) \ - CHECK_VECTOR_OR_SCALAR_TYPE(p_result) \ - \ - /* get operand */ \ - SpvReflectValue operand1 = {0}; \ - GET_OPERAND((simple_op_module), (simple_op_node), 4, &operand1, maxRecursion) \ - CHECK_IS_INTEGER_TYPE(&operand1) \ - CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) \ - \ - SpvReflectValue operand2 = {0}; \ - GET_OPERAND((simple_op_module), (simple_op_node), 5, &operand2, maxRecursion) \ - CHECK_IS_INTEGER_TYPE(&operand2) \ - CHECK_VECTOR_OR_SCALAR_TYPE(&operand2) \ - \ - /* op1 and result must have same width */ \ - CHECK_WIDTH_MATCH((p_result), &operand1) \ - uint32_t res_width = (p_result)->type->traits.numeric.scalar.width; \ - \ - /* vectors must be of same size */ \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), &operand1, &operand2); \ - \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { \ - (p_result)->values[i].undefined_value = 1; \ - } \ - /* load the shift number, set undefined flag if larger than result width*/ \ - uint8_t shift_num; \ - switch (operand2.type->traits.numeric.scalar.width) { \ - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - case 32: \ - { \ - uint32_t shift = operand2.values[i].value.uint32_bool_value; \ - if (operand1.values[i].undefined_value || shift >= res_width) { \ - (p_result)->values[i].undefined_value = 1; \ - } \ - shift_num = (uint8_t)shift; \ - } \ - break; \ - case 64: \ - { \ - uint64_t shift = operand2.values[i].value.uint64_value; \ - if (operand1.values[i].undefined_value || shift >= res_width) { \ - (p_result)->values[i].undefined_value = 1; \ - } \ - shift_num = (uint8_t)shift; \ - } \ - break; \ - } \ - switch (res_width) { \ - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - case 32: \ - { \ - uint32_t data = operand1.values[i].value.uint32_bool_value; \ - SHIFT_OP_32_BIT_HOOK_PRE \ - data operation##= shift_num; \ - SHIFT_OP_32_BIT_HOOK_POST \ - (p_result)->values[i].value.uint32_bool_value = data; \ - } \ - break; \ - case 64: \ - { \ - uint64_t data = operand1.values[i].value.uint64_value; \ - SHIFT_OP_64_BIT_HOOK_PRE \ - data operation##= shift_num; \ - SHIFT_OP_64_BIT_HOOK_POST \ - (p_result)->values[i].value.uint64_value = data; \ - } \ - break; \ - } \ - } \ - return SPV_REFLECT_RESULT_SUCCESS; \ +#define DO_SHIFT_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion) \ +{ \ + CHECK_INSTRUCTION_SIZE((simple_op_node), 6) \ + /* check result type */ \ + CHECK_IS_INTEGER_TYPE((p_result)) \ + CHECK_VECTOR_OR_SCALAR_TYPE(p_result) \ + \ + /* get operand */ \ + SpvReflectValue operand1 = {0}; \ + GET_OPERAND((simple_op_module), (simple_op_node), 4, &operand1, maxRecursion) \ + CHECK_IS_INTEGER_TYPE(&operand1) \ + CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) \ + \ + SpvReflectValue operand2 = {0}; \ + GET_OPERAND((simple_op_module), (simple_op_node), 5, &operand2, maxRecursion) \ + CHECK_IS_INTEGER_TYPE(&operand2) \ + CHECK_VECTOR_OR_SCALAR_TYPE(&operand2) \ + \ + /* op1 and result must have same width */ \ + CHECK_WIDTH_MATCH((p_result), &operand1) \ + uint32_t res_width = (p_result)->type->traits.numeric.scalar.width; \ + \ + /* vectors must be of same size */ \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), &operand1, &operand2) \ + \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1.data.numeric.vector.value[i].undefined_value \ + || operand2.data.numeric.vector.value[i].undefined_value) { \ + (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ + } \ + /* load the shift number, set undefined flag if larger than result width*/ \ + uint8_t shift_num; \ + switch (operand2.type->traits.numeric.scalar.width) { \ + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + case 32: \ + { \ + uint32_t shift = operand2.data.numeric.vector.value[i].value.uint32_bool_value; \ + if (operand1.data.numeric.vector.value[i].undefined_value || shift >= res_width) { \ + (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ + } \ + shift_num = (uint8_t)shift; \ + } \ + break; \ + case 64: \ + { \ + uint64_t shift = operand2.data.numeric.vector.value[i].value.uint64_value; \ + if (operand1.data.numeric.vector.value[i].undefined_value || shift >= res_width) { \ + (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ + } \ + shift_num = (uint8_t)shift; \ + } \ + break; \ + } \ + switch (res_width) { \ + default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + case 32: \ + { \ + uint32_t data = operand1.data.numeric.vector.value[i].value.uint32_bool_value; \ + SHIFT_OP_32_BIT_HOOK_PRE \ + data operation##= shift_num; \ + SHIFT_OP_32_BIT_HOOK_POST \ + (p_result)->data.numeric.vector.value[i].value.uint32_bool_value = data; \ + } \ + break; \ + case 64: \ + { \ + uint64_t data = operand1.data.numeric.vector.value[i].value.uint64_value; \ + SHIFT_OP_64_BIT_HOOK_PRE \ + data operation##= shift_num; \ + SHIFT_OP_64_BIT_HOOK_POST \ + (p_result)->data.numeric.vector.value[i].value.uint64_value = data; \ + } \ + break; \ + } \ + } \ + return SPV_REFLECT_RESULT_SUCCESS; \ } -#include - #define DO_BINARY_BOOLEAN_LOGICAL_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion) \ { \ CHECK_INSTRUCTION_SIZE((simple_op_node), 6) \ @@ -5645,14 +5687,16 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), &operand1, &operand2) \ \ for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1.values[i].undefined_value operation operand2.values[i].undefined_value) { \ - (p_result)->values[i].undefined_value = 1; \ + if (operand1.data.numeric.vector.value[i].undefined_value \ + operation operand2.data.numeric.vector.value[i].undefined_value) { \ + (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ } \ /* write to correct offset */ \ - (p_result)->values[i].value.uint32_bool_value \ - = operand1.values[i].value.uint32_bool_value operation operand2.values[i].value.uint32_bool_value; \ + (p_result)->data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1.data.numeric.vector.value[i].value.uint32_bool_value \ + operation operand2.data.numeric.vector.value[i].value.uint32_bool_value; \ } \ - return SPV_REFLECT_RESULT_SUCCESS; \ + return SPV_REFLECT_RESULT_SUCCESS; \ } #define DO_BINARY_INTEGER_LOGICAL_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion, _32bit_member, _64bit_member)\ @@ -5679,18 +5723,21 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), &operand1, &operand2) \ \ for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1.values[i].undefined_value || operand2.values[i].undefined_value) { \ - (p_result)->values[i].undefined_value = 1; \ + if (operand1.data.numeric.vector.value[i].undefined_value \ + || operand2.data.numeric.vector.value[i].undefined_value) { \ + (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ } \ switch (operand1.type->traits.numeric.scalar.width) { \ default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ case 32: \ - (p_result)->values[i].value.uint32_bool_value \ - = operand1.values[i].value.##_32bit_member operation operand2.values[i].value.##_32bit_member; \ + (p_result)->data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1.data.numeric.vector.value[i].value.##_32bit_member \ + operation operand2.data.numeric.vector.value[i].value.##_32bit_member; \ break; \ case 64: \ - (p_result)->values[i].value.uint32_bool_value \ - = operand1.values[i].value.##_64bit_member operation operand2.values[i].value.##_64bit_member; \ + (p_result)->data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1.data.numeric.vector.value[i].value.##_64bit_member \ + operation operand2.data.numeric.vector.value[i].value.##_64bit_member; \ break; \ } \ } \ @@ -5702,7 +5749,6 @@ SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint #define DO_BINARY_SINTEGER_LOGICAL_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion) \ DO_BINARY_INTEGER_LOGICAL_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion, sint32_value, sint64_value) - // Used for calculating specialization constants. // The switches are not necessary for littel endian cpu, // but still there just in case. @@ -5721,17 +5767,19 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; case SpvOpConstantTrue: { - result->values[0].value.uint32_bool_value = 1; + result->type = NULL; + result->data.numeric.scalar.value.uint32_bool_value = 1; } return SPV_REFLECT_RESULT_SUCCESS; case SpvOpConstantFalse: { - result->values[0].value.uint32_bool_value = 0; + result->type = NULL; + result->data.numeric.scalar.value.uint32_bool_value = 0; } return SPV_REFLECT_RESULT_SUCCESS; case SpvOpConstant: CONSTANT_RESULT: - return GetScalarConstant(p_module, p_node, &result->values[0], &result->type); + return GetScalarConstant(p_module, p_node, &result->data.numeric.scalar, &result->type); case SpvOpSpecConstantTrue: case SpvOpSpecConstantFalse: case SpvOpSpecConstant: { @@ -5742,7 +5790,7 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint res = GetSpecContantById(p_module, p_node->decorations.specialization_constant.value, &p_constant); if (res != SPV_REFLECT_RESULT_SUCCESS) return res; result->type = p_constant->type; - result->values[0] = p_constant->current_value; + result->data.numeric.scalar = p_constant->current_value; } return SPV_REFLECT_RESULT_SUCCESS; case SpvOpSpecConstantComposite: @@ -5750,8 +5798,8 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint // only support compositing vector types for now... // vectors are needed for spv compiled to WorkgroupSize builtin // in expressing actual localsize - res = GetTypeByTypeId(p_module, p_node->result_type_id, &result->type); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + result->type = FindType(p_module, p_node->result_type_id); + if (!result->type) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; // compositing types if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; @@ -5776,15 +5824,15 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint ||(operandi.type && ((operandi.type->type_flags & SCALAR_TYPE_FLAGS) != (result->type->type_flags & SCALAR_TYPE_FLAGS)))) { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } - result->values[i] = operandi.values[0]; + result->data.numeric.vector.value[i] = operandi.data.numeric.scalar; } } return SPV_REFLECT_RESULT_SUCCESS; case SpvOpSpecConstantOp: { // operation has result type id, thus must be typed - res = GetTypeByTypeId(p_module, p_node->result_type_id, &result->type); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; + result->type = FindType(p_module, p_node->result_type_id); + if (!result->type) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; // only vector and scalar types of int/bool/float types implemented // only OpSelect, OpUndef and access chain instructions can work with non-vector or scalar types @@ -5809,11 +5857,11 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint } if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { for (uint32_t i = 0; i < result->type->traits.numeric.vector.component_count; ++i) { - result->values[i].undefined_value = 1; + result->data.numeric.vector.value[i].undefined_value = 1; } } else { - result->values[0].undefined_value = 1; + result->data.numeric.scalar.undefined_value = 1; } } return SPV_REFLECT_RESULT_SUCCESS; @@ -5844,33 +5892,33 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint // now do the job for (uint32_t i = 0; i < vec_size; ++i) { - result->values[i].undefined_value = operand1.values->undefined_value; + result->data.numeric.vector.value[i].undefined_value = operand1.data.numeric.vector.value[i].undefined_value; switch (operand1.type->traits.numeric.scalar.width) { default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; case 32: { - int32_t data = operand1.values[i].value.sint32_value; + int32_t data = operand1.data.numeric.vector.value[i].value.sint32_value; switch (result->type->traits.numeric.scalar.width) { default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; case 32: - result->values[i].value.sint32_value = data; + result->data.numeric.vector.value[i].value.sint32_value = data; break; case 64: - result->values[i].value.sint64_value = (int64_t)data; + result->data.numeric.vector.value[i].value.sint64_value = (int64_t)data; break; } } break; case 64: { - int64_t data = operand1.values[i].value.sint64_value; + int64_t data = operand1.data.numeric.vector.value[i].value.sint64_value; switch (result->type->traits.numeric.scalar.width) { default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; case 32: - result->values[i].value.sint32_value = (int32_t)data; + result->data.numeric.vector.value[i].value.sint32_value = (int32_t)data; break; case 64: - result->values[i].value.sint64_value = data; + result->data.numeric.vector.value[i].value.sint64_value = data; break; } } @@ -5906,33 +5954,33 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint // now do the job for (uint32_t i = 0; i < vec_size; ++i) { - result->values[i].undefined_value = operand1.values->undefined_value; + result->data.numeric.vector.value[i].undefined_value = operand1.data.numeric.vector.value[i].undefined_value; switch (operand1.type->traits.numeric.scalar.width) { default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; case 32: { - uint32_t data = operand1.values[i].value.uint32_bool_value; + uint32_t data = operand1.data.numeric.vector.value[i].value.uint32_bool_value; switch (result->type->traits.numeric.scalar.width) { default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; case 32: - result->values[i].value.uint32_bool_value = data; + result->data.numeric.vector.value[i].value.uint32_bool_value = data; break; case 64: - result->values[i].value.uint64_value = (uint64_t)data; + result->data.numeric.vector.value[i].value.uint64_value = (uint64_t)data; break; } } break; case 64: { - uint64_t data = operand1.values[i].value.uint64_value; + uint64_t data = operand1.data.numeric.vector.value[i].value.uint64_value; switch (result->type->traits.numeric.scalar.width) { default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; case 32: - result->values[i].value.uint32_bool_value = (uint32_t)data; + result->data.numeric.vector.value[i].value.uint32_bool_value = (uint32_t)data; break; case 64: - result->values[i].value.uint64_value = data; + result->data.numeric.vector.value[i].value.uint64_value = data; break; } } @@ -5965,7 +6013,7 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint // now do the job for (uint32_t i = 0; i < vec_size; ++i) { - result->values[i].undefined_value = operand1.values->undefined_value; + result->data.numeric.vector.value[i].undefined_value = operand1.data.numeric.vector.value[i].undefined_value; switch (operand1.type->traits.numeric.scalar.width) { default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; case 32: @@ -5973,10 +6021,10 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint switch (result->type->traits.numeric.scalar.width) { default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; case 32: - result->values[i].value.float32_value = operand1.values[i].value.float32_value; + result->data.numeric.vector.value[i].value.float32_value = operand1.data.numeric.vector.value[i].value.float32_value; break; case 64: - result->values[i].value.float64_value = (double)operand1.values[i].value.float32_value; + result->data.numeric.vector.value[i].value.float64_value = (double)operand1.data.numeric.vector.value[i].value.float32_value; break; } break; @@ -5985,10 +6033,10 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint switch (result->type->traits.numeric.scalar.width) { default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; case 32: - result->values[i].value.float32_value = (float)operand1.values[i].value.float64_value; + result->data.numeric.vector.value[i].value.float32_value = (float)operand1.data.numeric.vector.value[i].value.float64_value; break; case 64: - result->values[i].value.float64_value = operand1.values[i].value.float64_value; + result->data.numeric.vector.value[i].value.float64_value = operand1.data.numeric.vector.value[i].value.float64_value; break; } } @@ -6044,12 +6092,12 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint #undef SIMPLE_BINARY_OP_32_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ - result->values[i].undefined_value = 1; \ + result->data.numeric.vector.value[i].undefined_value = 1; \ } #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_64_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ - result->values[i].undefined_value = 1; \ + result->data.numeric.vector.value[i].undefined_value = 1; \ } DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, /, maxRecursion) #undef SIMPLE_BINARY_OP_32_BIT_HOOK @@ -6065,12 +6113,12 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint #undef SIMPLE_BINARY_OP_32_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ - result->values[i].undefined_value = 1; \ + result->data.numeric.vector.value[i].undefined_value = 1; \ } #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_64_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ - result->values[i].undefined_value = 1; \ + result->data.numeric.vector.value[i].undefined_value = 1; \ } DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, %, maxRecursion) #undef SIMPLE_BINARY_OP_32_BIT_HOOK @@ -6082,7 +6130,7 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint #undef SIMPLE_BINARY_OP_32_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ - result->values[i].undefined_value = 1; \ + result->data.numeric.vector.value[i].undefined_value = 1; \ } \ else if (data != 0) { \ int sign1 = 0, sign2 = 0; \ @@ -6096,7 +6144,7 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_64_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ - result->values[i].undefined_value = 1; \ + result->data.numeric.vector.value[i].undefined_value = 1; \ } \ else if (data != 0) { \ int sign1 = 0, sign2 = 0; \ @@ -6153,10 +6201,154 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, & , maxRecursion) // Do not support compostion of vectors for now... - case SpvOpVectorShuffle: + case SpvOpVectorShuffle: + { + /* check result type*/ + CHECK_IS_INTEGER_TYPE(result) + CHECK_VECTOR_OR_SCALAR_TYPE(result) + if (!(result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + SpvReflectValue operand1 = {0}; + GET_OPERAND((p_module), (p_node), 4, &operand1, maxRecursion) + CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) + if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand1.type->component_type_id != result->type->component_type_id) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // cannot skip if type comes with result... + SpvReflectValue operand2 = {0}; + GET_OPERAND((p_module), (p_node), 5, &operand2, maxRecursion) + if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type->component_type_id != result->type->component_type_id) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + // instruction size must be: + // OpSpecConstantOp result_type result_id VectorShuffle vec1 vec2 comp1 comp2 .... + CHECK_INSTRUCTION_SIZE(p_node, 6 + result->type->traits.numeric.vector.component_count) + + // now do the job... + for (uint32_t i = 0; i < result->type->traits.numeric.vector.component_count; ++i) { + uint32_t mapped_component; + CHECKED_READU32(p_parser, p_node->word_offset + 6 + i, mapped_component) + if (mapped_component == 0xFFFFFFFF) { + result->data.numeric.vector.value[i].undefined_value = 1; + } + else if (mapped_component >= operand1.type->traits.numeric.vector.component_count + operand2.type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + } + else if (mapped_component < operand1.type->traits.numeric.vector.component_count) { + result->data.numeric.vector.value[i] = operand1.data.numeric.vector.value[mapped_component]; + } + else { + result->data.numeric.vector.value[i] = operand2.data.numeric.vector.value[mapped_component - operand1.type->traits.numeric.vector.component_count]; + } + } + return SPV_REFLECT_RESULT_SUCCESS; + } + // only support vector types for now... case SpvOpCompositeExtract: + { + // check composite allowed flags + if (result->type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + // need to travers the composite tree down to last operand. + // currently only support vector composite type. + + SpvReflectValue operand1 = {0}; + GET_OPERAND((p_module), (p_node), 4, &operand1, maxRecursion) + if (operand1.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + uint32_t cur_offset = 5; + SpvReflectValueData* current_data = &operand1.data; + SpvReflectTypeDescription* current_type = operand1.type; + for (; cur_offset < p_node->word_count; ++cur_offset) { + uint32_t member_index; + CHECKED_READU32(p_parser, p_node->word_offset+cur_offset, member_index); + SpvReflectResult err = GetMemberByIndex(p_module, current_data, current_type, member_index, ¤t_data, ¤t_type); + if (err != SPV_REFLECT_RESULT_SUCCESS) { + return err; + } + } + if (current_type->id != result->type->id) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + SpvReflectResult err = CopyValueData(p_module, current_type, &result->data, current_data); + if (err != SPV_REFLECT_RESULT_SUCCESS) { + return err; + } + } + return SPV_REFLECT_RESULT_SUCCESS; case SpvOpCompositeInsert: - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + { + + if (result->type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + + SpvReflectValue operand2 = {0}; + GET_OPERAND((p_module), (p_node), 5, &operand2, maxRecursion) + if (operand2.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + if (operand2.type) { + if (operand2.type->id != result->type->id) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + } + else { + if (result->type->type_flags != SPV_REFLECT_TYPE_FLAG_BOOL) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + } + result->data = operand2.data; + + SpvReflectValue operand1 = {0}; + GET_OPERAND((p_module), (p_node), 4, &operand1, maxRecursion) + + uint32_t cur_offset = 6; + SpvReflectValueData* current_data = &result->data; + SpvReflectTypeDescription* current_type = result->type; + for (; cur_offset < p_node->word_count; ++cur_offset) { + uint32_t member_index; + CHECKED_READU32(p_parser, p_node->word_offset + cur_offset, member_index); + SpvReflectResult err = GetMemberByIndex(p_module, current_data, current_type, member_index, ¤t_data, ¤t_type); + if (err != SPV_REFLECT_RESULT_SUCCESS) { + return err; + } + } + + if (!current_type) { + if (operand1.type && (operand1.type->type_flags != SPV_REFLECT_TYPE_FLAG_BOOL)) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + } + else { + if (operand1.type) { + if (current_type->id != operand1.type->id) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + } + else if (current_type->type_flags != SPV_REFLECT_TYPE_FLAG_BOOL) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + } + SpvReflectResult err = CopyValueData(p_module, current_type, current_data, &operand1.data); + if (err != SPV_REFLECT_RESULT_SUCCESS) { + return err; + } + } + return SPV_REFLECT_RESULT_SUCCESS; case SpvOpLogicalOr: DO_BINARY_BOOLEAN_LOGICAL_OPERATION(result, p_module, p_node, ||, maxRecursion) @@ -6179,14 +6371,14 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint /* vectors must be of same size */ uint32_t vec_size = 1; - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, (result), &operand1) + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, result, &operand1) for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1.values[i].undefined_value) { - (result)->values[i].undefined_value = 1; + if (operand1.data.numeric.vector.value[i].undefined_value) { + result->data.numeric.vector.value[i].undefined_value = 1; } /* write to correct offset */ - (result)->values[i].value.uint32_bool_value = !operand1.values[i].value.uint32_bool_value; + result->data.numeric.vector.value[i].value.uint32_bool_value = !operand1.data.numeric.vector.value[i].value.uint32_bool_value; } } return SPV_REFLECT_RESULT_SUCCESS; @@ -6214,63 +6406,60 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint // cannot skip if type comes with result... SpvReflectValue operand2 = {0}; GET_OPERAND((p_module), (p_node), 5, &operand2, maxRecursion) - if (operand2.type != result->type) { + if (operand2.type->id != result->type->id) { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } SpvReflectValue operand3 = {0}; GET_OPERAND((p_module), (p_node), 6, &operand3, maxRecursion) - if (operand3.type != result->type) { + if (operand3.type->id != result->type->id) { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } uint32_t vec_size = 1; // result can be vector if operand is scalar. CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, &operand1, result); + if (vec_size != 1) { if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1.values[i].undefined_value) { - result->values[i].undefined_value = 1; + if (operand1.data.numeric.vector.value[i].undefined_value) { + result->data.numeric.vector.value[i].undefined_value = 1; } - if (operand1.values[i].value.uint32_bool_value) { - if (operand2.values[i].undefined_value) { - result->values[i].undefined_value = 1; + if (operand1.data.numeric.vector.value[i].value.uint32_bool_value) { + if (operand2.data.numeric.vector.value[i].undefined_value) { + result->data.numeric.vector.value[i].undefined_value = 1; } - result->values[i].value = operand2.values[i].value; + result->data.numeric.vector.value[i].value = operand2.data.numeric.vector.value[i].value; } else { - if (operand3.values[i].undefined_value) { - result->values[i].undefined_value = 1; + if (operand3.data.numeric.vector.value[i].undefined_value) { + result->data.numeric.vector.value[i].undefined_value = 1; } - result->values[i].value = operand3.values[i].value; + result->data.numeric.vector.value[i].value = operand3.data.numeric.vector.value[i].value; } } } else { // deep copy value, inherit undefined value - if (operand1.values[0].undefined_value) { - // we shouldn't care about content here... - for (uint32_t i = 0; i < SPV_REFLECT_MAX_VECTOR_DIMS; ++i) { - result->values[i].undefined_value = 1; - } + + // we can't deal with other types for now... + if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; } - if (operand1.values[0].value.uint32_bool_value) { - for (uint32_t i = 0; i < SPV_REFLECT_MAX_VECTOR_DIMS; ++i) { - if (operand2.values[i].undefined_value) { - result->values[i].undefined_value = 1; - } - result->values[i].value = operand2.values[i].value; - } + + if (operand1.data.numeric.scalar.value.uint32_bool_value) { + *result = operand2; } else { + *result = operand3; + } + if (operand1.data.numeric.vector.value[0].undefined_value) { + // we shouldn't care about content here... for (uint32_t i = 0; i < SPV_REFLECT_MAX_VECTOR_DIMS; ++i) { - if (operand3.values[i].undefined_value) { - result->values[i].undefined_value = 1; - } - result->values[i].value = operand3.values[i].value; + result->data.numeric.vector.value[i].undefined_value = 1; } } } diff --git a/spirv_reflect.h b/spirv_reflect.h index 3efb8722..314ebc1b 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -336,25 +336,18 @@ typedef struct SpvReflectTypeDescription { uint32_t member_count; struct SpvReflectTypeDescription* members; + + // for vector, array and matrix types + uint32_t component_type_id; } SpvReflectTypeDescription; /*! @struct SpvReflectSpecializationConstant */ -typedef enum SpvReflectScalarType { - SPV_REFLECT_SCALAR_TYPE_UNKNOWN = 0, - SPV_REFLECT_SCALAR_TYPE_BOOL = 1, - SPV_REFLECT_SCALAR_TYPE_INT = 2, - SPV_REFLECT_SCALAR_TYPE_FLOAT = 3, -} SpvReflectScalarType; -// 16 bit floating point can be common. Just a bitwise representation here... -// c++ requires c++14 standard for non static union members to have same address. -// c seems to have always assumed this. typedef uint16_t spv_reflect_float16_t; -typedef struct SpvReflectScalarValue { - // strongly typed for evaluation purpose +typedef struct SpvReflectScalarValueData { union { /* small types not implemented yet... */ uint8_t uint8_value; @@ -372,26 +365,38 @@ typedef struct SpvReflectScalarValue { } value; // for use with OpUndef int undefined_value; -} SpvReflectScalarValue; +} SpvReflectScalarValueData; + +typedef struct SpvReflectVectorValueData { + SpvReflectScalarValueData value[SPV_REFLECT_MAX_VECTOR_DIMS]; +} SpvReflectVectorValueData; // only scalar, vector types can evaluate values for now... +// this struct is not meant to be created on user stack, +// instead in a internal dictionary and give user const ptr to read. +typedef union SpvReflectValueNumericData { + SpvReflectScalarValueData scalar; + SpvReflectVectorValueData vector; +} SpvReflectValueNumericData; + +typedef union SpvReflectValueData { + SpvReflectValueNumericData numeric; +} SpvReflectValueData; + typedef struct SpvReflectValue { - // may be null if boolean, coming from OpSpecConstantTrue/OpSpecConstantFalse - // but type found through return type id is never null. SpvReflectTypeDescription* type; - SpvReflectScalarValue values[SPV_REFLECT_MAX_VECTOR_DIMS]; -} SpvReflectValue; + SpvReflectValueData data; +}SpvReflectValue; typedef struct SpvReflectSpecializationConstant { uint32_t spirv_id; uint32_t constant_id; - SpvReflectScalarType general_type; SpvReflectTypeDescription* type; const char* name; - SpvReflectScalarValue default_value; - SpvReflectScalarValue current_value; + SpvReflectScalarValueData default_value; + SpvReflectScalarValueData current_value; } SpvReflectSpecializationConstant; From 06da6a4fa1d5c0dc3b27595a027b180a5b89f0b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Mon, 1 Aug 2022 12:48:10 +0800 Subject: [PATCH 10/44] Switch to another branch Test and much work is needed to remove dependency on parser. (Need to store constant expressions in a separate representation. Potentially also removing redundant evaluation) --- spirv_reflect.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spirv_reflect.c b/spirv_reflect.c index 0ba3deb1..7a020e85 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -6451,9 +6451,11 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint } if (operand1.data.numeric.scalar.value.uint32_bool_value) { + // need deep copy if complex *result = operand2; } else { + // need deep copy if complex *result = operand3; } if (operand1.data.numeric.vector.value[0].undefined_value) { From 94b217553137b6667f360b88cf4dfc1af4b0206d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Mon, 1 Aug 2022 21:54:22 +0800 Subject: [PATCH 11/44] Added state tracking and ownership of result Remove dependency on parser. Still, FindType needs the module pointer... --- common/output_stream.cpp | 74 +- common/output_stream.h | 2 +- main.cpp | 2 +- spirv_reflect.c | 1443 +++++++++++++++++++++++--------------- spirv_reflect.h | 37 +- 5 files changed, 924 insertions(+), 634 deletions(-) diff --git a/common/output_stream.cpp b/common/output_stream.cpp index 92dfeaf4..8724329e 100644 --- a/common/output_stream.cpp +++ b/common/output_stream.cpp @@ -600,7 +600,7 @@ std::string ToStringComponentType(const SpvReflectTypeDescription& type, uint32_ } void ParseBlockMembersToTextLines( - const spv_reflect::ShaderModule& obj, + spv_reflect::ShaderModule& obj, const char* indent, int indent_depth, bool flatten_cbuffers, const std::string& parent_name, uint32_t member_count, const SpvReflectBlockVariable* p_members, std::vector* p_text_lines) { const char* t = indent; @@ -664,10 +664,10 @@ void ParseBlockMembersToTextLines( // if (dim > 0) { if (dim == 0xFFFFFFFF) { - SpvReflectValue val{}; - SpvReflectResult res = obj.EvaluateResult(member.array.spec_constant_op_ids[array_dim_index], val); - if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val.type->traits.numeric.scalar.width == 32)) { - dim = val.data.numeric.scalar.value.uint32_bool_value; + const SpvReflectValue* val; + SpvReflectResult res = obj.EvaluateResult(member.array.spec_constant_op_ids[array_dim_index], &val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { + dim = val->data.numeric.scalar.value.uint32_bool_value; } } ss_array << "[" << dim << "]"; @@ -707,10 +707,10 @@ void ParseBlockMembersToTextLines( for (uint32_t array_dim_index = 0; array_dim_index < member.array.dims_count; ++array_dim_index) { uint32_t dim = member.array.dims[array_dim_index]; if (dim == 0xFFFFFFFF) { - SpvReflectValue val{}; - SpvReflectResult res = obj.EvaluateResult(member.array.spec_constant_op_ids[array_dim_index], val); - if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val.type->traits.numeric.scalar.width == 32)) { - dim = val.data.numeric.scalar.value.uint32_bool_value; + const SpvReflectValue* val; + SpvReflectResult res = obj.EvaluateResult(member.array.spec_constant_op_ids[array_dim_index], &val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { + dim = val->data.numeric.scalar.value.uint32_bool_value; } } ss_array << "[" << dim << "]"; @@ -728,7 +728,7 @@ void ParseBlockMembersToTextLines( } } -void ParseBlockVariableToTextLines(const spv_reflect::ShaderModule& obj, const char* indent, bool flatten_cbuffers, const SpvReflectBlockVariable& block_var, std::vector* p_text_lines) +void ParseBlockVariableToTextLines(spv_reflect::ShaderModule& obj, const char* indent, bool flatten_cbuffers, const SpvReflectBlockVariable& block_var, std::vector* p_text_lines) { // Begin block TextLine tl = {}; @@ -944,7 +944,7 @@ void StreamWriteTextLines(std::ostream& os, const char* indent, bool flatten_cbu } } -void StreamWritePushConstantsBlock(std::ostream& os, const spv_reflect::ShaderModule& shader, const SpvReflectBlockVariable& obj, bool flatten_cbuffers, const char* indent) +void StreamWritePushConstantsBlock(std::ostream& os, spv_reflect::ShaderModule& shader, const SpvReflectBlockVariable& obj, bool flatten_cbuffers, const char* indent) { const char* t = indent; os << t << "spirv id : " << obj.spirv_id << "\n"; @@ -963,7 +963,7 @@ void StreamWritePushConstantsBlock(std::ostream& os, const spv_reflect::ShaderMo } } -void StreamWriteDescriptorBinding(std::ostream& os, const spv_reflect::ShaderModule& shader, const SpvReflectDescriptorBinding& obj, bool write_set, bool flatten_cbuffers, const char* indent) +void StreamWriteDescriptorBinding(std::ostream& os, spv_reflect::ShaderModule& shader, const SpvReflectDescriptorBinding& obj, bool write_set, bool flatten_cbuffers, const char* indent) { const char* t = indent; os << t << "spirv id : " << obj.spirv_id << "\n"; @@ -1017,7 +1017,7 @@ void StreamWriteDescriptorBinding(std::ostream& os, const spv_reflect::ShaderMod } } -void StreamWriteInterfaceVariable(std::ostream& os, const spv_reflect::ShaderModule& shader, const SpvReflectInterfaceVariable& obj, const char* indent) +void StreamWriteInterfaceVariable(std::ostream& os, spv_reflect::ShaderModule& shader, const SpvReflectInterfaceVariable& obj, const char* indent) { const char* t = indent; os << t << "spirv id : " << obj.spirv_id << "\n"; @@ -1038,10 +1038,10 @@ void StreamWriteInterfaceVariable(std::ostream& os, const spv_reflect::ShaderMod for (uint32_t dim_index = 0; dim_index < obj.array.dims_count; ++dim_index) { uint32_t dim = obj.array.dims[dim_index]; if (dim == 0xFFFFFFFF) { - SpvReflectValue val{}; - SpvReflectResult res = shader.EvaluateResult(obj.array.spec_constant_op_ids[dim_index], val); - if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val.type->traits.numeric.scalar.width == 32)) { - dim = val.data.numeric.scalar.value.uint32_bool_value; + const SpvReflectValue* val; + SpvReflectResult res = shader.EvaluateResult(obj.array.spec_constant_op_ids[dim_index], &val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { + dim = val->data.numeric.scalar.value.uint32_bool_value; } } os << "[" << obj.array.dims[dim_index] << "]"; @@ -1134,7 +1134,7 @@ void StreamWriteSpecializationConstant(std::ostream& os, const SpvReflectSpecial } } -void StreamWriteEntryPoint(std::ostream& os, const spv_reflect::ShaderModule& shader, const SpvReflectEntryPoint& obj, const char* indent) +void StreamWriteEntryPoint(std::ostream& os, spv_reflect::ShaderModule& shader, const SpvReflectEntryPoint& obj, const char* indent) { os << indent << "entry point : " << obj.name; os << " (stage=" << ToStringShaderStage(obj.shader_stage) << ")"; @@ -1147,13 +1147,13 @@ void StreamWriteEntryPoint(std::ostream& os, const spv_reflect::ShaderModule& sh os << "local size hint : "; } if(obj.local_size.flags & 4) { - SpvReflectValue val{}; - SpvReflectResult res = shader.EvaluateResult(obj.local_size.x, val); - if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == (SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_VECTOR)) - && (val.type->traits.numeric.scalar.width == 32)) { - os << "(" << val.data.numeric.vector.value[0].value.uint32_bool_value << ", " - << val.data.numeric.vector.value[1].value.uint32_bool_value << ", " - << val.data.numeric.vector.value[2].value.uint32_bool_value << ")"; + const SpvReflectValue* val; + SpvReflectResult res = shader.EvaluateResult(obj.local_size.x, &val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == (SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_VECTOR)) + && (val->type->traits.numeric.scalar.width == 32)) { + os << "(" << val->data.numeric.vector.value[0].value.uint32_bool_value << ", " + << val->data.numeric.vector.value[1].value.uint32_bool_value << ", " + << val->data.numeric.vector.value[2].value.uint32_bool_value << ")"; } else { os << "(failed evaluation of WorkGroupSize Builtin)"; @@ -1161,25 +1161,25 @@ void StreamWriteEntryPoint(std::ostream& os, const spv_reflect::ShaderModule& sh } else if(obj.local_size.flags & 1) { os << "("; - SpvReflectValue val = {0}; - SpvReflectResult res = shader.EvaluateResult(obj.local_size.x, val); - if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val.type->traits.numeric.scalar.width == 32)) { - os << val.data.numeric.scalar.value.uint32_bool_value; + const SpvReflectValue* val; + SpvReflectResult res = shader.EvaluateResult(obj.local_size.x, &val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { + os << val->data.numeric.scalar.value.uint32_bool_value; } else { os << "unknown"; } os << ", "; - res = shader.EvaluateResult(obj.local_size.y, val); - if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val.type->traits.numeric.scalar.width == 32)) { - os << val.data.numeric.scalar.value.uint32_bool_value; + res = shader.EvaluateResult(obj.local_size.y, &val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { + os << val->data.numeric.scalar.value.uint32_bool_value; } else { os << "unknown"; } os << ", "; - res = shader.EvaluateResult(obj.local_size.z, val); - if ((res == SPV_REFLECT_RESULT_SUCCESS) && val.type && (val.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val.type->traits.numeric.scalar.width == 32)) { - os << val.data.numeric.vector.value[2].value.uint32_bool_value; + res = shader.EvaluateResult(obj.local_size.z, &val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { + os << val->data.numeric.vector.value[2].value.uint32_bool_value; } else { os << "unknown"; @@ -1192,7 +1192,7 @@ void StreamWriteEntryPoint(std::ostream& os, const spv_reflect::ShaderModule& sh } } -void StreamWriteShaderModule(std::ostream& os, const spv_reflect::ShaderModule& obj, const char* indent) +void StreamWriteShaderModule(std::ostream& os, spv_reflect::ShaderModule& obj, const char* indent) { (void)indent; os << "generator : " << ToStringGenerator(obj.GetShaderModule().generator) << "\n"; @@ -1217,7 +1217,7 @@ void StreamWriteShaderModule(std::ostream& os, const spv_reflect::ShaderModule& #define USE_ASSERT(x) ((void)(x)) #endif -void WriteReflection(const spv_reflect::ShaderModule& obj, bool flatten_cbuffers, std::ostream& os) +void WriteReflection(spv_reflect::ShaderModule& obj, bool flatten_cbuffers, std::ostream& os) { const char* t = " "; const char* tt = " "; diff --git a/common/output_stream.h b/common/output_stream.h index b69c70a7..fc4f1784 100644 --- a/common/output_stream.h +++ b/common/output_stream.h @@ -25,7 +25,7 @@ std::string ToStringComponentType(const SpvReflectTypeDescription& type, uint32_ std::string ToStringType(SpvSourceLanguage src_lang, const SpvReflectTypeDescription& type); //std::ostream& operator<<(std::ostream& os, const spv_reflect::ShaderModule& obj); -void WriteReflection(const spv_reflect::ShaderModule& obj, bool flatten_cbuffers, std::ostream& os); +void WriteReflection(spv_reflect::ShaderModule& obj, bool flatten_cbuffers, std::ostream& os); class SpvReflectToYaml { public: diff --git a/main.cpp b/main.cpp index 6b53a14c..214019b3 100644 --- a/main.cpp +++ b/main.cpp @@ -107,7 +107,7 @@ int main(int argn, char** argv) std::vector spv_data(size); spv_ifstream.read(spv_data.data(), size); - spv_reflect::ShaderModule reflection(spv_data.size(), spv_data.data(), SPV_REFLECT_MODULE_FLAG_EVALUATE_SPEC_CONSTANT); + spv_reflect::ShaderModule reflection(spv_data.size(), spv_data.data(), SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT); if (reflection.GetResult() != SPV_REFLECT_RESULT_SUCCESS) { std::cerr << "ERROR: could not process '" << input_spv_path << "' (is it a valid SPIR-V bytecode?)" << std::endl; diff --git a/spirv_reflect.c b/spirv_reflect.c index 7a020e85..9f110451 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -217,6 +217,46 @@ typedef struct SpvReflectPrvParser { } SpvReflectPrvParser; // clang-format on +typedef enum SpvReflectEvaluationState { + SPV_REFLECT_EVALUATION_STATE_UNINITIALIZED = 0, + // for tracking recursion + SPV_REFLECT_EVALUATION_STATE_WORKING = 1, + SPV_REFLECT_EVALUATION_STATE_DONE = 2, + // for possible update tracking + SPV_REFLECT_EVALUATION_STATE_UPDATED = 3, + // failed evaluation + SPV_REFLECT_EVALUATION_STATE_FAILED = 4 +}SpvReflectEvaluationState; + +// clang-format off +typedef struct SpvReflectPrvEvaluationNode { + uint32_t result_id; + SpvOp op; + uint32_t word_offset; + uint32_t word_count; + SpvReflectEvaluationState evaluation_state; + SpvReflectValue value; + + SpvReflectSpecializationConstant* spec_const; +} SpvReflectPrvEvaluationNode; +// clang-format on + +// clang-format off +typedef struct SpvReflectPrvEvaluation { + // original code if no-copy, else it's a copy of constant instructions + size_t spirv_word_count; + uint32_t* spirv_code; + + uint32_t node_count; + SpvReflectPrvEvaluationNode* nodes; + + // ohh I hope I could decouple this... But FindType uses this... + // just a reference + SpvReflectShaderModule* member_type_finder; +} SpvReflectPrvEvaluation; +// clang-format on + + static uint32_t Max( uint32_t a, uint32_t b) @@ -522,6 +562,21 @@ static SpvReflectPrvNode* FindNode( return p_node; } +static SpvReflectPrvEvaluationNode* FindEvaluationNode( + SpvReflectPrvEvaluation* p_eval, + uint32_t result_id) +{ + SpvReflectPrvEvaluationNode* p_node = NULL; + for (size_t i = 0; i < p_eval->node_count; ++i) { + SpvReflectPrvEvaluationNode* p_elem = &(p_eval->nodes[i]); + if (p_elem->result_id == result_id) { + p_node = p_elem; + break; + } + } + return p_node; +} + static SpvReflectTypeDescription* FindType(const SpvReflectShaderModule* p_module, uint32_t type_id) { SpvReflectTypeDescription* p_type = NULL; @@ -3387,6 +3442,42 @@ static SpvReflectResult ParseExecutionModes( return SPV_REFLECT_RESULT_SUCCESS; } +static bool EvalCodeInRange( + const SpvReflectPrvEvaluation* p_eval, + uint32_t index) +{ + bool in_range = false; + if (IsNotNull(p_eval)) { + in_range = (index < p_eval->spirv_word_count); + } + return in_range; +} + +static SpvReflectResult EvalReadU32( + const SpvReflectPrvEvaluation* p_eval, + uint32_t word_offset, + uint32_t* p_value) +{ + assert(IsNotNull(p_eval)); + assert(IsNotNull(p_eval->spirv_code)); + assert(EvalCodeInRange(p_eval, word_offset)); + SpvReflectResult result = SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_EOF; + if (IsNotNull(p_eval) && IsNotNull(p_eval->spirv_code) && EvalCodeInRange(p_eval, word_offset)) { + *p_value = *(p_eval->spirv_code + word_offset); + result = SPV_REFLECT_RESULT_SUCCESS; + } + return result; +} + +#define EVAL_CHECKED_READU32(eval, word_offset, value, res, cleanup) \ + { \ + res = EvalReadU32(eval, \ + word_offset, (uint32_t*)&(value)); \ + if (res != SPV_REFLECT_RESULT_SUCCESS) { \ + goto cleanup; \ + } \ + } + #define SCALAR_TYPE_FLAGS (SPV_REFLECT_TYPE_FLAG_BOOL | SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_FLOAT) #define SCALAR_DISALLOWED_FLAGS (~0 ^ SCALAR_TYPE_FLAGS) #define VECTOR_TYPE_FLAGS (SCALAR_TYPE_FLAGS | SPV_REFLECT_TYPE_FLAG_VECTOR) @@ -3395,22 +3486,44 @@ static SpvReflectResult ParseExecutionModes( #define COMPOSITE_TYPE_FLAGS (VECTOR_TYPE_FLAGS|SPV_REFLECT_TYPE_FLAG_MATRIX|SPV_REFLECT_TYPE_FLAG_STRUCT|SPV_REFLECT_TYPE_FLAG_ARRAY) #define COMPOSITE_DISALLOWED_FLAGS (~0 ^ COMPOSITE_TYPE_FLAGS) -static SpvReflectResult GetScalarConstant(const SpvReflectShaderModule* p_module, SpvReflectPrvNode* p_node, - SpvReflectScalarValueData* result, SpvReflectTypeDescription** type) +// getting constant also happens before evaluation is created. +static SpvReflectResult EvalGetScalarConstant(const SpvReflectPrvEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node) { - SpvReflectPrvParser* p_parser = p_module->_internal->parser; + SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS; + if(p_node->value.type->type_flags & SCALAR_DISALLOWED_FLAGS) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + uint32_t low_word; + EVAL_CHECKED_READU32(p_eval, p_node->word_offset + 3, low_word, result, CLEANUP); + // There is no alignment requirements in c/cpp for unions + if (p_node->value.type->traits.numeric.scalar.width == 32) { + memcpy(&p_node->value.data.numeric.scalar.value.uint32_bool_value, &low_word, 4); + } + else if (p_node->value.type->traits.numeric.scalar.width ==64) { + uint32_t high_word; + EVAL_CHECKED_READU32(p_eval, p_node->word_offset + 4, high_word, result, CLEANUP); + uint64_t combined = low_word | (((uint64_t)high_word) << 32); + memcpy(&p_node->value.data.numeric.scalar.value.uint64_value, &combined, 8); + } + else { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + CLEANUP: + return result; +} +static SpvReflectResult ParserGetScalarConstant(const SpvReflectShaderModule* p_module, SpvReflectPrvParser* p_parser, SpvReflectPrvNode* p_node, + SpvReflectScalarValueData* result, SpvReflectTypeDescription** type) +{ SpvReflectTypeDescription* d_type = FindType(p_module, p_node->result_type_id); if (!d_type) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; - if(d_type->type_flags & SCALAR_DISALLOWED_FLAGS) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + if (d_type->type_flags & SCALAR_DISALLOWED_FLAGS) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; uint32_t low_word; CHECKED_READU32(p_parser, p_node->word_offset + 3, low_word); // There is no alignment requirements in c/cpp for unions if (d_type->traits.numeric.scalar.width == 32) { memcpy(&result->value.uint32_bool_value, &low_word, 4); } - else if (d_type->traits.numeric.scalar.width ==64) { + else if (d_type->traits.numeric.scalar.width == 64) { uint32_t high_word; CHECKED_READU32(p_parser, p_node->word_offset + 4, high_word); uint64_t combined = low_word | (((uint64_t)high_word) << 32); @@ -3423,12 +3536,32 @@ static SpvReflectResult GetScalarConstant(const SpvReflectShaderModule* p_module return SPV_REFLECT_RESULT_SUCCESS; } +#define MODULE_EVALUATION_FLAGS (SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT | SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT_NO_COPY) + +#define IS_CONSTANT_OP(op_code) \ + (((op_code) == SpvOpSpecConstantTrue) || ((op_code) == SpvOpSpecConstantFalse) || ((op_code) == SpvOpSpecConstant) \ + || ((op_code) == SpvOpSpecConstantOp) || ((op_code) == SpvOpSpecConstantComposite) || ((op_code) == SpvOpConstant) \ + || ((op_code) == SpvOpConstantTrue) || ((op_code) == SpvOpConstantFalse) || ((op_code) == SpvOpConstantComposite) \ + || ((op_code) == SpvOpConstantNull) || ((op_code) == SpvOpConstantSampler) || ((op_code) == SpvOpConstantPipeStorage) \ + || ((op_code) == SpvOpSpecConstantCompositeContinuedINTEL) || ((op_code) == SpvOpConstantFunctionPointerINTEL) \ + || ((op_code) == SpvOpConstantCompositeContinuedINTEL)) + +// defined later.. +static SpvReflectSpecializationConstant* GetSpecContantById(const SpvReflectShaderModule* p_module, uint32_t constant_id); static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) { p_module->specialization_constant_count = 0; p_module->specialization_constants = NULL; + + uint32_t constant_instruction_num = 0; + uint32_t instruction_size = 0; for (size_t i = 0; i < p_parser->node_count; ++i) { SpvReflectPrvNode* p_node = &(p_parser->nodes[i]); + // constant types need to be tracked after parser is dead... + if (IS_CONSTANT_OP(p_node->op)) { + constant_instruction_num++; + instruction_size += p_node->word_count; + } if (p_node->op == SpvOpSpecConstantTrue || p_node->op == SpvOpSpecConstantFalse || p_node->op == SpvOpSpecConstant) { p_module->specialization_constant_count++; } @@ -3470,7 +3603,7 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars case SpvOpSpecConstant: { SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS; SpvReflectScalarValueData default_value = { 0 }; - result = GetScalarConstant(p_module, p_node, &default_value, &p_module->specialization_constants[index].type); + result = ParserGetScalarConstant(p_module, p_parser, p_node, &default_value, &p_module->specialization_constants[index].type); if (result != SPV_REFLECT_RESULT_SUCCESS) return result; p_module->specialization_constants[index].default_value = default_value; p_module->specialization_constants[index].current_value = p_module->specialization_constants[index].default_value; @@ -3491,9 +3624,68 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars index++; } + // need to evaluate expr later on... + if (p_module->_internal->module_flags & MODULE_EVALUATION_FLAGS) { + p_module->_internal->evaluator = (SpvReflectPrvEvaluation*)calloc(1, sizeof(SpvReflectPrvEvaluation)); + // needed for FindType for constituent types + p_module->_internal->evaluator->member_type_finder = p_module; + p_module->_internal->evaluator->node_count = constant_instruction_num; + p_module->_internal->evaluator->nodes = (SpvReflectPrvEvaluationNode*)calloc(constant_instruction_num,sizeof(SpvReflectPrvEvaluationNode)); + if (p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT_NO_COPY) { + // use original code for evaluation. + p_module->_internal->evaluator->spirv_code = p_module->_internal->spirv_code; + p_module->_internal->evaluator->spirv_word_count = p_module->_internal->spirv_word_count; + } + else if (p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT) { + // need to copy instructions from code for later evaluation. + p_module->_internal->evaluator->spirv_code = (uint32_t*)malloc(instruction_size * sizeof(uint32_t)); + p_module->_internal->evaluator->spirv_word_count = instruction_size; + } + + // need to update correct offset in new code if not no-copy + uint32_t current_offset = 0; + uint32_t current_cinst = 0; + for (size_t i = 0; i < p_parser->node_count; ++i) { + SpvReflectPrvNode* p_node = &(p_parser->nodes[i]); + // constant types need to be tracked after parser is dead... + if (IS_CONSTANT_OP(p_node->op)) { + p_module->_internal->evaluator->nodes[current_cinst].op = p_node->op; + p_module->_internal->evaluator->nodes[current_cinst].result_id = p_node->result_id; + p_module->_internal->evaluator->nodes[current_cinst].word_count = p_node->word_count; + p_module->_internal->evaluator->nodes[current_cinst].value.type = FindType(p_module, p_node->result_type_id); + if (!p_module->_internal->evaluator->nodes[current_cinst].value.type) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; + } + p_module->_internal->evaluator->nodes[current_cinst].evaluation_state = SPV_REFLECT_EVALUATION_STATE_UNINITIALIZED; + p_module->_internal->evaluator->nodes[current_cinst].spec_const = NULL; + if (p_node->decorations.specialization_constant.value != INVALID_VALUE) { + p_module->_internal->evaluator->nodes[current_cinst].spec_const = GetSpecContantById(p_module, p_node->decorations.specialization_constant.value); + } + if (p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT_NO_COPY) { + p_module->_internal->evaluator->nodes[current_cinst].word_offset = p_node->word_offset; + } + else { + p_module->_internal->evaluator->nodes[current_cinst].word_offset = current_offset; + memcpy(p_module->_internal->evaluator->spirv_code + current_offset, p_module->_internal->spirv_code + p_node->word_offset, 4 * p_node->word_count); + } + ++current_cinst; + current_offset += p_node->word_count; + } + } + } + return SPV_REFLECT_RESULT_SUCCESS; } +static void DestroyEvaluator(SpvReflectPrvEvaluation* evaluator, bool owns_code) +{ + SafeFree(evaluator->nodes); + if (owns_code) { + SafeFree(evaluator->spirv_code); + } +} + + static SpvReflectResult ParsePushConstantBlocks( SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) @@ -3803,13 +3995,13 @@ static SpvReflectResult CreateShaderModule( } // parser now works in internal field of p_module. - // SpvReflectPrvParser parser = { 0 }; - SpvReflectPrvParser* parser = (SpvReflectPrvParser*)calloc(1,sizeof(SpvReflectPrvParser)); + SpvReflectPrvParser parser = { 0 }; + // SpvReflectPrvParser* parser = (SpvReflectPrvParser*)calloc(1,sizeof(SpvReflectPrvParser)); SpvReflectResult result = CreateParser(p_module->_internal->spirv_size, p_module->_internal->spirv_code, - parser); + &parser); // used by spec constant parsing GetScalarConstant - p_module->_internal->parser = parser; + //p_module->_internal->parser = parser; // Generator { @@ -3818,38 +4010,38 @@ static SpvReflectResult CreateShaderModule( } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseNodes(parser); + result = ParseNodes(&parser); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseStrings(parser); + result = ParseStrings(&parser); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseSource(parser, p_module); + result = ParseSource(&parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseFunctions(parser); + result = ParseFunctions(&parser); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseMemberCounts(parser); + result = ParseMemberCounts(&parser); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseNames(parser); + result = ParseNames(&parser); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseDecorations(parser); + result = ParseDecorations(&parser); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } // Start of reflection data parsing if (result == SPV_REFLECT_RESULT_SUCCESS) { - p_module->source_language = parser->source_language; - p_module->source_language_version = parser->source_language_version; + p_module->source_language = parser.source_language; + p_module->source_language_version = parser.source_language_version; // Zero out descriptor set data p_module->descriptor_set_count = 0; @@ -3860,11 +4052,11 @@ static SpvReflectResult CreateShaderModule( } } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseTypes(parser, p_module); + result = ParseTypes(&parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseDescriptorBindings(parser, p_module); + result = ParseDescriptorBindings(&parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { @@ -3876,15 +4068,15 @@ static SpvReflectResult CreateShaderModule( SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseDescriptorBlocks(parser, p_module); + result = ParseDescriptorBlocks(&parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParsePushConstantBlocks(parser, p_module); + result = ParsePushConstantBlocks(&parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseEntryPoints(parser, p_module); + result = ParseEntryPoints(&parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS && p_module->entry_point_count > 0) { @@ -3909,12 +4101,12 @@ static SpvReflectResult CreateShaderModule( SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseExecutionModes(parser, p_module); + result = ParseExecutionModes(&parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } // WorkGroupSize builtin needs to update entry point localsize member if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseSpecializationConstants(parser, p_module); + result = ParseSpecializationConstants(&parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } @@ -3923,16 +4115,7 @@ static SpvReflectResult CreateShaderModule( spvReflectDestroyShaderModule(p_module); } - // parser is needed for evaluating specconstants - if (flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_SPEC_CONSTANT) { - p_module->_internal->parser = parser; - } - else { - DestroyParser(parser); - SafeFree(parser) - } - - + DestroyParser(&parser); return result; } @@ -4076,9 +4259,10 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module) if ((p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_NO_COPY) == 0) { SafeFree(p_module->_internal->spirv_code); } - if (p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_SPEC_CONSTANT) { - DestroyParser(p_module->_internal->parser); - SafeFree(p_module->_internal->parser); + + if (p_module->_internal->module_flags & MODULE_EVALUATION_FLAGS) { + DestroyEvaluator(p_module->_internal->evaluator, !(p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT_NO_COPY)); + SafeFree(p_module->_internal->evaluator) } // Free internal @@ -5260,16 +5444,16 @@ const char* spvReflectBlockVariableTypeName( return p_var->type_description->type_name; } -SpvReflectResult GetSpecContantById(const SpvReflectShaderModule* p_module, uint32_t constant_id, SpvReflectSpecializationConstant** pp_constant) + + +SpvReflectSpecializationConstant* GetSpecContantById(const SpvReflectShaderModule* p_module, uint32_t constant_id) { - SpvReflectResult res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; for (uint32_t i = 0; i < p_module->specialization_constant_count; ++i) { if (p_module->specialization_constants[i].constant_id == constant_id) { - *pp_constant = &p_module->specialization_constants[i]; - return SPV_REFLECT_RESULT_SUCCESS; + return &p_module->specialization_constants[i]; } } - return res; + return NULL; } SpvReflectResult GetMemberByIndex(const SpvReflectShaderModule* p_module, const SpvReflectValueData* mother, const SpvReflectTypeDescription* mother_type, @@ -5299,7 +5483,7 @@ SpvReflectResult GetMemberByIndex(const SpvReflectShaderModule* p_module, const } } -SpvReflectResult CopyValueData(const SpvReflectShaderModule* p_module, const SpvReflectTypeDescription* type, SpvReflectValueData* dst, SpvReflectValueData* src) +SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflectValueData* dst, SpvReflectValueData* src) { if (!type || !(type->type_flags & VECTOR_DISALLOWED_FLAGS)) { if (!type || !(type->type_flags & SCALAR_DISALLOWED_FLAGS)) { @@ -5324,259 +5508,265 @@ SpvReflectResult CopyValueData(const SpvReflectShaderModule* p_module, const Spv } \ } -#define CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_result, p_op1) \ +#define CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_result, p_op1, res, CLEANUP) \ { \ if ((p_result)->type && (p_result)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ if (!((p_op1)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ } \ if ((p_op1)->type->traits.numeric.vector.component_count != (p_result)->type->traits.numeric.vector.component_count) { \ - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ } \ vec_size = (p_result)->type->traits.numeric.vector.component_count; \ } \ } -#define CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, p_result, p_op1, p_op2)\ +#define CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, p_result, p_op1, p_op2, res, CLEANUP)\ { \ /* may be scalar boolean if type == null, but never p_result */ \ if ((p_result)->type && (p_result)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ if(!(p_op1)->type || !(p_op2)->type) { \ - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ } \ if (!((p_op1)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ } \ if (!((p_op2)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ } \ if ((p_op1)->type->traits.numeric.vector.component_count != (p_result)->type->traits.numeric.vector.component_count) { \ - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ } \ if ((p_op2)->type->traits.numeric.vector.component_count != (p_result)->type->traits.numeric.vector.component_count) { \ - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ } \ vec_size = (p_result)->type->traits.numeric.vector.component_count; \ } \ } -#define CHECK_WIDTH_MATCH(p_value1, p_value2) \ +#define CHECK_WIDTH_MATCH(p_value1, p_value2, res, CLEANUP) \ { \ if ((p_value2)->type->traits.numeric.scalar.width != (p_value1)->type->traits.numeric.scalar.width) { \ - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ } \ } -#define CHECK_IS_BASIC_TYPE_EXCEPT_BOOL(p_result, b_type) \ +#define CHECK_IS_BASIC_TYPE(p_result, b_type, res, CLEANUP) \ { \ - if(!(p_result)->type) { \ - /* is result of opconstanttrue, etc. Boolean... */ \ - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - } \ if(((p_result)->type->type_flags & SCALAR_TYPE_FLAGS) != b_type) { \ - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ } \ } -#define CHECK_IS_INTEGER_TYPE(p_result) CHECK_IS_BASIC_TYPE_EXCEPT_BOOL(p_result, SPV_REFLECT_TYPE_FLAG_INT) -#define CHECK_IS_FLOAT_TYPE(p_result) CHECK_IS_BASIC_TYPE_EXCEPT_BOOL(p_result, SPV_REFLECT_TYPE_FLAG_FLOAT) -#define CHECK_IS_BOOLEAN_TYPE(p_result) \ -{ \ - if((p_result)->type) { \ - if(((p_result)->type->type_flags & SCALAR_TYPE_FLAGS) != SPV_REFLECT_TYPE_FLAG_BOOL) { \ - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - } \ - } \ -} +#define CHECK_IS_INTEGER_TYPE(p_result, res, CLEANUP) CHECK_IS_BASIC_TYPE(p_result, SPV_REFLECT_TYPE_FLAG_INT, res, CLEANUP) +#define CHECK_IS_FLOAT_TYPE(p_result, res, CLEANUP) CHECK_IS_BASIC_TYPE(p_result, SPV_REFLECT_TYPE_FLAG_FLOAT, res, CLEANUP) +#define CHECK_IS_BOOLEAN_TYPE(p_result, res, CLEANUP) CHECK_IS_BASIC_TYPE(p_result, SPV_REFLECT_TYPE_FLAG_BOOL, res, CLEANUP) + -#define CHECK_VECTOR_OR_SCALAR_TYPE(p_result) \ +#define CHECK_VECTOR_OR_SCALAR_TYPE(p_result, res, CLEANUP) \ { \ if ((p_result)->type && ((p_result)->type->type_flags & VECTOR_DISALLOWED_FLAGS)) { \ - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ } \ } \ -#define GET_OPERAND(p_module, p_node, offset, p_operand, maxRecursion) \ -{ \ - uint32_t operand_id; \ - CHECKED_READU32(p_module->_internal->parser, p_node->word_offset + offset, operand_id); \ - SpvReflectResult result_get_op = EvaluateResultImpl(p_module, operand_id, (p_operand), maxRecursion - 1); \ - if (result_get_op != SPV_REFLECT_RESULT_SUCCESS) return result_get_op; \ +#define GET_OPERAND(eval, p_node, offset, p_operand, res, CLEANUP) \ +{ \ + uint32_t operand_id; \ + EVAL_CHECKED_READU32(eval, p_node->word_offset + offset, operand_id, res, CLEANUP); \ + res = EvaluateResultImpl(eval, operand_id, &(p_operand)); \ + if (res != SPV_REFLECT_RESULT_SUCCESS) goto CLEANUP; \ } #define SIMPLE_UNARY_OP_32_BIT_HOOK #define SIMPLE_UNARY_OP_64_BIT_HOOK -#define DO_SIMPLE_UNARY_INTEGER_OPERATION(p_result, simple_op_module, simple_op_node, maxRecursion) \ -{ \ - CHECK_INSTRUCTION_SIZE((simple_op_node), 5) \ - \ - /* check result type */ \ - CHECK_IS_INTEGER_TYPE((p_result)) \ - CHECK_VECTOR_OR_SCALAR_TYPE((p_result)) \ - \ - /* get operand */ \ - SpvReflectValue operand1 = {0}; \ - GET_OPERAND((simple_op_module), (simple_op_node), 4, &operand1, maxRecursion) \ - /* check type here */ \ - CHECK_IS_INTEGER_TYPE(&operand1) \ - CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) \ - \ - /* component width must match. */ \ - CHECK_WIDTH_MATCH((p_result), &operand1) \ - \ - /* vector size must match */ \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, (p_result), &operand1)\ - \ - /* now do the job */ \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - (p_result)->data.numeric.vector.value[i].undefined_value \ - = operand1.data.numeric.vector.value[i].undefined_value; \ - switch (operand1.type->traits.numeric.scalar.width) { \ - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - case 32: \ - /* 32 bit integer */ \ - { \ - int32_t data = operand1.data.numeric.vector.value[i].value.sint32_value; \ - SIMPLE_UNARY_OP_32_BIT_HOOK \ - (p_result)->data.numeric.vector.value[i].value.sint32_value = data; \ - } \ - break; \ - case 64: \ - /* 64 bit integer */ \ - { \ - int64_t data = operand1.data.numeric.vector.value[i].value.sint64_value; \ - SIMPLE_UNARY_OP_64_BIT_HOOK \ - (p_result)->data.numeric.vector.value[i].value.sint64_value = data; \ - } \ - break; \ - } \ - } \ - return SPV_REFLECT_RESULT_SUCCESS; \ +#define DO_SIMPLE_UNARY_INTEGER_OPERATION(p_result, simple_op_eval, simple_op_node, res, CLEANUP) \ +{ \ + CHECK_INSTRUCTION_SIZE((simple_op_node), 5) \ + \ + /* check result type */ \ + CHECK_IS_INTEGER_TYPE((p_result), res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE((p_result), res, CLEANUP) \ + \ + /* get operand */ \ + SpvReflectValue* operand1 = NULL; \ + GET_OPERAND((simple_op_eval), (simple_op_node), 4, operand1, res, CLEANUP) \ + /* check type here */ \ + CHECK_IS_INTEGER_TYPE(operand1, res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) \ + \ + /* component width must match. */ \ + CHECK_WIDTH_MATCH((p_result), operand1, res, CLEANUP) \ + \ + /* vector size must match */ \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, (p_result), operand1, res, CLEANUP) \ + \ + /* now do the job */ \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + (p_result)->data.numeric.vector.value[i].undefined_value \ + = operand1->data.numeric.vector.value[i].undefined_value; \ + switch (operand1->type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + /* 32 bit integer */ \ + { \ + int32_t data = operand1->data.numeric.vector.value[i].value.sint32_value; \ + SIMPLE_UNARY_OP_32_BIT_HOOK \ + (p_result)->data.numeric.vector.value[i].value.sint32_value = data; \ + } \ + break; \ + case 64: \ + /* 64 bit integer */ \ + { \ + int64_t data = operand1->data.numeric.vector.value[i].value.sint64_value; \ + SIMPLE_UNARY_OP_64_BIT_HOOK \ + (p_result)->data.numeric.vector.value[i].value.sint64_value = data; \ + } \ + break; \ + } \ + } \ } #define SIMPLE_BINARY_OP_32_BIT_HOOK #define SIMPLE_BINARY_OP_64_BIT_HOOK -#define DO_SIMPLE_BINARY_INTEGER_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion) \ -{ \ - { \ - CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ - /* check result type*/ \ - CHECK_IS_INTEGER_TYPE(p_result) \ - CHECK_VECTOR_OR_SCALAR_TYPE((p_result)) \ - \ - /* get operand */ \ - SpvReflectValue operand1 = {0}; \ - GET_OPERAND(simple_op_module, simple_op_node, 4, &operand1, maxRecursion) \ - CHECK_IS_INTEGER_TYPE(&operand1) \ - CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) \ - \ - SpvReflectValue operand2 = {0}; \ - GET_OPERAND(simple_op_module, simple_op_node, 5, &operand2, maxRecursion) \ - CHECK_IS_INTEGER_TYPE(&operand2) \ - CHECK_VECTOR_OR_SCALAR_TYPE(&operand2) \ - \ - /* component width must be same */ \ - CHECK_WIDTH_MATCH(p_result, &operand1) \ - CHECK_WIDTH_MATCH(p_result, &operand2) \ - \ - /* vectors must be of same size */ \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), &operand1, &operand2) \ - /* now do the job, width unknown but same, all three sign unkown \ - but still, since spv defines signed integer as 2-compliment, \ - so do recent c/cpp standard, directly adding uint should be enough.*/ \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1.data.numeric.vector.value[i].undefined_value \ - || operand2.data.numeric.vector.value[i].undefined_value) { \ - (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ - } \ - switch ((p_result)->type->traits.numeric.scalar.width) { \ - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - case 32: \ - { \ - /* load data into int32_t*/ \ - int32_t data1 = operand1.data.numeric.vector.value[i].value.sint32_value; \ - int32_t data2 = operand2.data.numeric.vector.value[i].value.sint32_value; \ - int32_t data = data1 operation data2; \ - SIMPLE_BINARY_OP_32_BIT_HOOK \ - /* write to correct offset */ \ - (p_result)->data.numeric.vector.value[i].value.sint32_value = data; \ - } \ - break; \ - case 64: \ - { \ - /* load data into int64_t*/ \ - int64_t data1 = operand1.data.numeric.vector.value[i].value.sint64_value; \ - int64_t data2 = operand2.data.numeric.vector.value[i].value.sint64_value; \ - int64_t data = data1 operation data2; \ - SIMPLE_BINARY_OP_32_BIT_HOOK \ - /* write to correct offset */ \ - (p_result)->data.numeric.vector.value[i].value.sint64_value = data; \ - } \ - break; \ - } \ - } \ - } \ - return SPV_REFLECT_RESULT_SUCCESS; \ +#define DO_SIMPLE_BINARY_INTEGER_OPERATION(p_result, simple_op_eval, simple_op_node, operation, res, CLEANUP) \ +{ \ + { \ + CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ + /* check result type*/ \ + CHECK_IS_INTEGER_TYPE(p_result, res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE((p_result), res, CLEANUP) \ + \ + /* get operand */ \ + SpvReflectValue* operand1 = NULL; \ + GET_OPERAND(simple_op_eval, simple_op_node, 4, operand1, res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE(operand1, res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) \ + \ + SpvReflectValue* operand2 = NULL; \ + GET_OPERAND(simple_op_eval, simple_op_node, 5, operand2, res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE(operand2, res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(operand2, res, CLEANUP) \ + \ + /* component width must be same */ \ + CHECK_WIDTH_MATCH(p_result, operand1, res, CLEANUP) \ + CHECK_WIDTH_MATCH(p_result, operand2, res, CLEANUP) \ + \ + /* vectors must be of same size */ \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), operand1, operand2, res, CLEANUP) \ + /* now do the job, width unknown but same, all three sign unkown \ + but still, since spv defines signed integer as 2-compliment, \ + so do recent c/cpp standard, directly adding uint should be enough.*/ \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->data.numeric.vector.value[i].undefined_value \ + || operand2->data.numeric.vector.value[i].undefined_value) { \ + (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ + } \ + switch ((p_result)->type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + { \ + /* load data into int32_t*/ \ + int32_t data1 = operand1->data.numeric.vector.value[i].value.sint32_value; \ + int32_t data2 = operand2->data.numeric.vector.value[i].value.sint32_value; \ + int32_t data = data1 operation data2; \ + SIMPLE_BINARY_OP_32_BIT_HOOK \ + /* write to correct offset */ \ + (p_result)->data.numeric.vector.value[i].value.sint32_value = data; \ + } \ + break; \ + case 64: \ + { \ + /* load data into int64_t*/ \ + int64_t data1 = operand1->data.numeric.vector.value[i].value.sint64_value; \ + int64_t data2 = operand2->data.numeric.vector.value[i].value.sint64_value; \ + int64_t data = data1 operation data2; \ + SIMPLE_BINARY_OP_32_BIT_HOOK \ + /* write to correct offset */ \ + (p_result)->data.numeric.vector.value[i].value.sint64_value = data; \ + } \ + break; \ + } \ + } \ + } \ } -#define DO_UNSIGNED_INTEGER_DIVISION(p_result, simple_op_module, simple_op_node, operation, maxRecursion) \ -{ \ - CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ - /* check result type */ \ - CHECK_IS_INTEGER_TYPE(p_result) \ - CHECK_VECTOR_OR_SCALAR_TYPE(p_result) \ - if ((p_result)->type->traits.numeric.scalar.signedness) { \ - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - } \ - \ - /* get operand */ \ - SpvReflectValue operand1 = {0}; \ - GET_OPERAND(simple_op_module, simple_op_node, 4, &operand1, maxRecursion) \ - if ((!operand1.type) || operand1.type->id != (p_result)->type->id) { \ - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - } \ - SpvReflectValue operand2 = {0}; \ - GET_OPERAND(simple_op_module, simple_op_node, 5, &operand2, maxRecursion) \ - if ((!operand2.type) || operand2.type->id != (p_result)->type->id) { \ - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - } \ - \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), &operand1, &operand2) \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1.data.numeric.vector.value[i].undefined_value \ - || operand2.data.numeric.vector.value[i].undefined_value) { \ - (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ - } \ - switch ((p_result)->type->traits.numeric.scalar.width) { \ - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - case 32: \ - { \ - (p_result)->data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1.data.numeric.vector.value[i].value.uint32_bool_value \ - operation operand2.data.numeric.vector.value[i].value.uint32_bool_value; \ - if (operand2.data.numeric.vector.value[i].value.uint32_bool_value == 0) { \ - (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ - } \ - } \ - break; \ - case 64: \ - { \ - (p_result)->data.numeric.vector.value[i].value.uint64_value \ - = operand1.data.numeric.vector.value[i].value.uint64_value \ - operation operand2.data.numeric.vector.value[i].value.uint64_value; \ - if (operand2.data.numeric.vector.value[i].value.uint64_value == 0) { \ - (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ - } \ - } \ - break; \ - } \ - } \ - return SPV_REFLECT_RESULT_SUCCESS; \ +#define DO_UNSIGNED_INTEGER_DIVISION(p_result, simple_op_eval, simple_op_node, operation, res, CLEANUP) \ +{ \ + CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ + /* check result type */ \ + CHECK_IS_INTEGER_TYPE(p_result, res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(p_result, res, CLEANUP) \ + if ((p_result)->type->traits.numeric.scalar.signedness) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + \ + /* get operand */ \ + SpvReflectValue* operand1 = NULL; \ + GET_OPERAND(simple_op_eval, simple_op_node, 4, operand1, res, CLEANUP) \ + if ((!operand1->type) || operand1->type->id != (p_result)->type->id) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + SpvReflectValue* operand2 = NULL; \ + GET_OPERAND(simple_op_eval, simple_op_node, 5, operand2, res, CLEANUP) \ + if ((!operand2->type) || operand2->type->id != (p_result)->type->id) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), operand1, operand2, res, CLEANUP) \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->data.numeric.vector.value[i].undefined_value \ + || operand2->data.numeric.vector.value[i].undefined_value) { \ + (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ + } \ + switch ((p_result)->type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + { \ + (p_result)->data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1->data.numeric.vector.value[i].value.uint32_bool_value \ + operation operand2->data.numeric.vector.value[i].value.uint32_bool_value; \ + if (operand2->data.numeric.vector.value[i].value.uint32_bool_value == 0) { \ + (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ + } \ + } \ + break; \ + case 64: \ + { \ + (p_result)->data.numeric.vector.value[i].value.uint64_value \ + = operand1->data.numeric.vector.value[i].value.uint64_value \ + operation operand2->data.numeric.vector.value[i].value.uint64_value; \ + if (operand2->data.numeric.vector.value[i].value.uint64_value == 0) { \ + (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ + } \ + } \ + break; \ + } \ + } \ } #define SHIFT_OP_32_BIT_HOOK_PRE @@ -5584,45 +5774,47 @@ SpvReflectResult CopyValueData(const SpvReflectShaderModule* p_module, const Spv #define SHIFT_OP_32_BIT_HOOK_POST #define SHIFT_OP_64_BIT_HOOK_POST -#define DO_SHIFT_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion) \ +#define DO_SHIFT_OPERATION(p_result, simple_op_eval, simple_op_node, operation, res, CLEANUP) \ { \ CHECK_INSTRUCTION_SIZE((simple_op_node), 6) \ /* check result type */ \ - CHECK_IS_INTEGER_TYPE((p_result)) \ - CHECK_VECTOR_OR_SCALAR_TYPE(p_result) \ + CHECK_IS_INTEGER_TYPE((p_result), res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(p_result, res, CLEANUP) \ \ /* get operand */ \ - SpvReflectValue operand1 = {0}; \ - GET_OPERAND((simple_op_module), (simple_op_node), 4, &operand1, maxRecursion) \ - CHECK_IS_INTEGER_TYPE(&operand1) \ - CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) \ + SpvReflectValue* operand1 = NULL; \ + GET_OPERAND((simple_op_eval), (simple_op_node), 4, operand1, res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE(operand1, res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) \ \ - SpvReflectValue operand2 = {0}; \ - GET_OPERAND((simple_op_module), (simple_op_node), 5, &operand2, maxRecursion) \ - CHECK_IS_INTEGER_TYPE(&operand2) \ - CHECK_VECTOR_OR_SCALAR_TYPE(&operand2) \ + SpvReflectValue* operand2 = NULL; \ + GET_OPERAND((simple_op_eval), (simple_op_node), 5, operand2, res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE(operand2, res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(operand2, res, CLEANUP) \ \ /* op1 and result must have same width */ \ - CHECK_WIDTH_MATCH((p_result), &operand1) \ + CHECK_WIDTH_MATCH((p_result), operand1, res, CLEANUP) \ uint32_t res_width = (p_result)->type->traits.numeric.scalar.width; \ \ /* vectors must be of same size */ \ uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), &operand1, &operand2) \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), operand1, operand2, res, CLEANUP) \ \ for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1.data.numeric.vector.value[i].undefined_value \ - || operand2.data.numeric.vector.value[i].undefined_value) { \ + if (operand1->data.numeric.vector.value[i].undefined_value \ + || operand2->data.numeric.vector.value[i].undefined_value) { \ (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ } \ /* load the shift number, set undefined flag if larger than result width*/ \ uint8_t shift_num; \ - switch (operand2.type->traits.numeric.scalar.width) { \ - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + switch (operand2->type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ case 32: \ { \ - uint32_t shift = operand2.data.numeric.vector.value[i].value.uint32_bool_value; \ - if (operand1.data.numeric.vector.value[i].undefined_value || shift >= res_width) { \ + uint32_t shift = operand2->data.numeric.vector.value[i].value.uint32_bool_value; \ + if (operand1->data.numeric.vector.value[i].undefined_value || shift >= res_width) { \ (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ } \ shift_num = (uint8_t)shift; \ @@ -5630,8 +5822,8 @@ SpvReflectResult CopyValueData(const SpvReflectShaderModule* p_module, const Spv break; \ case 64: \ { \ - uint64_t shift = operand2.data.numeric.vector.value[i].value.uint64_value; \ - if (operand1.data.numeric.vector.value[i].undefined_value || shift >= res_width) { \ + uint64_t shift = operand2->data.numeric.vector.value[i].value.uint64_value; \ + if (operand1->data.numeric.vector.value[i].undefined_value || shift >= res_width) { \ (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ } \ shift_num = (uint8_t)shift; \ @@ -5639,10 +5831,12 @@ SpvReflectResult CopyValueData(const SpvReflectShaderModule* p_module, const Spv break; \ } \ switch (res_width) { \ - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ case 32: \ { \ - uint32_t data = operand1.data.numeric.vector.value[i].value.uint32_bool_value; \ + uint32_t data = operand1->data.numeric.vector.value[i].value.uint32_bool_value; \ SHIFT_OP_32_BIT_HOOK_PRE \ data operation##= shift_num; \ SHIFT_OP_32_BIT_HOOK_POST \ @@ -5651,7 +5845,7 @@ SpvReflectResult CopyValueData(const SpvReflectShaderModule* p_module, const Spv break; \ case 64: \ { \ - uint64_t data = operand1.data.numeric.vector.value[i].value.uint64_value; \ + uint64_t data = operand1->data.numeric.vector.value[i].value.uint64_value; \ SHIFT_OP_64_BIT_HOOK_PRE \ data operation##= shift_num; \ SHIFT_OP_64_BIT_HOOK_POST \ @@ -5660,94 +5854,93 @@ SpvReflectResult CopyValueData(const SpvReflectShaderModule* p_module, const Spv break; \ } \ } \ - return SPV_REFLECT_RESULT_SUCCESS; \ } -#define DO_BINARY_BOOLEAN_LOGICAL_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion) \ -{ \ - CHECK_INSTRUCTION_SIZE((simple_op_node), 6) \ - \ - /* check result type */ \ - CHECK_IS_BOOLEAN_TYPE((p_result)) \ - CHECK_VECTOR_OR_SCALAR_TYPE((p_result)) \ - \ - /* get operand */ \ - SpvReflectValue operand1 = {0}; \ - GET_OPERAND((simple_op_module), (simple_op_node), 4, &operand1, maxRecursion) \ - CHECK_IS_BOOLEAN_TYPE(&operand1) \ - CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) \ - \ - SpvReflectValue operand2 = {0}; \ - GET_OPERAND((simple_op_module), (simple_op_node), 5, &operand2, maxRecursion) \ - CHECK_IS_BOOLEAN_TYPE(&operand2) \ - CHECK_VECTOR_OR_SCALAR_TYPE(&operand2) \ - \ - /* vectors must be of same size */ \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), &operand1, &operand2) \ - \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1.data.numeric.vector.value[i].undefined_value \ - operation operand2.data.numeric.vector.value[i].undefined_value) { \ - (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ - } \ - /* write to correct offset */ \ - (p_result)->data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1.data.numeric.vector.value[i].value.uint32_bool_value \ - operation operand2.data.numeric.vector.value[i].value.uint32_bool_value; \ - } \ - return SPV_REFLECT_RESULT_SUCCESS; \ +#define DO_BINARY_BOOLEAN_LOGICAL_OPERATION(p_result, simple_op_eval, simple_op_node, operation, res, CLEANUP) \ +{ \ + CHECK_INSTRUCTION_SIZE((simple_op_node), 6) \ + \ + /* check result type */ \ + CHECK_IS_BOOLEAN_TYPE((p_result), res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE((p_result), res, CLEANUP) \ + \ + /* get operand */ \ + SpvReflectValue* operand1 = NULL; \ + GET_OPERAND((simple_op_eval), (simple_op_node), 4, operand1, res, CLEANUP) \ + CHECK_IS_BOOLEAN_TYPE(operand1, res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) \ + \ + SpvReflectValue* operand2 = NULL; \ + GET_OPERAND((simple_op_eval), (simple_op_node), 5, operand2, res, CLEANUP) \ + CHECK_IS_BOOLEAN_TYPE(operand2, res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(operand2, res, CLEANUP) \ + \ + /* vectors must be of same size */ \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), operand1, operand2, res, CLEANUP) \ + \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->data.numeric.vector.value[i].undefined_value \ + operation operand2->data.numeric.vector.value[i].undefined_value) { \ + (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ + } \ + /* write to correct offset */ \ + (p_result)->data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1->data.numeric.vector.value[i].value.uint32_bool_value \ + operation operand2->data.numeric.vector.value[i].value.uint32_bool_value; \ + } \ } -#define DO_BINARY_INTEGER_LOGICAL_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion, _32bit_member, _64bit_member)\ -{ \ - CHECK_INSTRUCTION_SIZE((simple_op_node), 6) \ - \ - /* check result type */ \ - CHECK_IS_BOOLEAN_TYPE((p_result)) \ - CHECK_VECTOR_OR_SCALAR_TYPE((p_result)) \ - \ - /* get operand */ \ - SpvReflectValue operand1 = {0}; \ - GET_OPERAND((simple_op_module), (simple_op_node), 4, &operand1, maxRecursion) \ - CHECK_IS_INTEGER_TYPE(&operand1) \ - CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) \ - \ - SpvReflectValue operand2 = {0}; \ - GET_OPERAND((simple_op_module), (simple_op_node), 5, &operand2, maxRecursion) \ - CHECK_IS_INTEGER_TYPE(&operand2) \ - CHECK_VECTOR_OR_SCALAR_TYPE(&operand2) \ - \ - /* vectors must be of same size */ \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), &operand1, &operand2) \ - \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1.data.numeric.vector.value[i].undefined_value \ - || operand2.data.numeric.vector.value[i].undefined_value) { \ - (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ - } \ - switch (operand1.type->traits.numeric.scalar.width) { \ - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - case 32: \ - (p_result)->data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1.data.numeric.vector.value[i].value.##_32bit_member \ - operation operand2.data.numeric.vector.value[i].value.##_32bit_member; \ - break; \ - case 64: \ - (p_result)->data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1.data.numeric.vector.value[i].value.##_64bit_member \ - operation operand2.data.numeric.vector.value[i].value.##_64bit_member; \ - break; \ - } \ - } \ - return SPV_REFLECT_RESULT_SUCCESS; \ +#define DO_BINARY_INTEGER_LOGICAL_OPERATION(p_result, simple_op_eval, simple_op_node, operation, _32bit_member, _64bit_member, res, CLEANUP) \ +{ \ + CHECK_INSTRUCTION_SIZE((simple_op_node), 6) \ + \ + /* check result type */ \ + CHECK_IS_BOOLEAN_TYPE((p_result), res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE((p_result), res, CLEANUP) \ + \ + /* get operand */ \ + SpvReflectValue* operand1 = NULL; \ + GET_OPERAND((simple_op_eval), (simple_op_node), 4, operand1, res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE(operand1, res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) \ + \ + SpvReflectValue* operand2 = NULL; \ + GET_OPERAND((simple_op_eval), (simple_op_node), 5, operand2, res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE(operand2, res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(operand2, res, CLEANUP) \ + \ + /* vectors must be of same size */ \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), operand1, operand2, res, CLEANUP) \ + \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->data.numeric.vector.value[i].undefined_value \ + || operand2->data.numeric.vector.value[i].undefined_value) { \ + (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ + } \ + switch (operand1->type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + (p_result)->data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1->data.numeric.vector.value[i].value.##_32bit_member \ + operation operand2->data.numeric.vector.value[i].value.##_32bit_member; \ + break; \ + case 64: \ + (p_result)->data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1->data.numeric.vector.value[i].value.##_64bit_member \ + operation operand2->data.numeric.vector.value[i].value.##_64bit_member; \ + break; \ + } \ + } \ } -#define DO_BINARY_UINTEGER_LOGICAL_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion) \ - DO_BINARY_INTEGER_LOGICAL_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion, uint32_bool_value, uint64_value) -#define DO_BINARY_SINTEGER_LOGICAL_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion) \ - DO_BINARY_INTEGER_LOGICAL_OPERATION(p_result, simple_op_module, simple_op_node, operation, maxRecursion, sint32_value, sint64_value) +#define DO_BINARY_UINTEGER_LOGICAL_OPERATION(p_result, simple_op_eval, simple_op_node, operation, res, CLEANUP) \ + DO_BINARY_INTEGER_LOGICAL_OPERATION(p_result, simple_op_eval, simple_op_node, operation, uint32_bool_value, uint64_value, res, CLEANUP) +#define DO_BINARY_SINTEGER_LOGICAL_OPERATION(p_result, simple_op_eval, simple_op_node, operation, res, CLEANUP) \ + DO_BINARY_INTEGER_LOGICAL_OPERATION(p_result, simple_op_eval, simple_op_node, operation, sint32_value, sint64_value, res, CLEANUP) // Used for calculating specialization constants. // The switches are not necessary for littel endian cpu, @@ -5755,54 +5948,65 @@ SpvReflectResult CopyValueData(const SpvReflectShaderModule* p_module, const Spv // memcpy is required since c/c++ have strict aliasing rules // access to signed and unsigned versions of same width integer's // address does not violate strict aliasing rules -SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint32_t result_id, SpvReflectValue* result, uint32_t maxRecursion) +SpvReflectResult EvaluateResultImpl(SpvReflectPrvEvaluation* p_eval, uint32_t result_id, const SpvReflectValue** p_result) { - if(!maxRecursion) return SPV_REFLECT_RESULT_ERROR_SPIRV_RECURSION; SpvReflectResult res = SPV_REFLECT_RESULT_SUCCESS; - SpvReflectPrvParser* p_parser = p_module->_internal->parser; - SpvReflectPrvNode* p_node = FindNode(p_parser, result_id); + SpvReflectPrvEvaluationNode* p_node = FindEvaluationNode(p_eval, result_id); if (!p_node) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; + *p_result = &p_node->value; + SpvReflectValue* result = &p_node->value; + if (!result->type) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; + } + if (p_node->evaluation_state == SPV_REFLECT_EVALUATION_STATE_FAILED) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + } + if (p_node->evaluation_state == SPV_REFLECT_EVALUATION_STATE_WORKING) { + p_node->evaluation_state = SPV_REFLECT_EVALUATION_STATE_FAILED; + return SPV_REFLECT_RESULT_ERROR_SPIRV_RECURSION; + } + if (p_node->evaluation_state == SPV_REFLECT_EVALUATION_STATE_DONE) { + return SPV_REFLECT_RESULT_SUCCESS; + } + p_node->evaluation_state = SPV_REFLECT_EVALUATION_STATE_WORKING; + switch (p_node->op) { default: - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + break; case SpvOpConstantTrue: { - result->type = NULL; result->data.numeric.scalar.value.uint32_bool_value = 1; } - return SPV_REFLECT_RESULT_SUCCESS; + break; case SpvOpConstantFalse: { - result->type = NULL; result->data.numeric.scalar.value.uint32_bool_value = 0; } - return SPV_REFLECT_RESULT_SUCCESS; + break; case SpvOpConstant: CONSTANT_RESULT: - return GetScalarConstant(p_module, p_node, &result->data.numeric.scalar, &result->type); + res = EvalGetScalarConstant(p_eval, p_node); + break; case SpvOpSpecConstantTrue: case SpvOpSpecConstantFalse: case SpvOpSpecConstant: { - if (p_node->decorations.specialization_constant.value == (uint32_t)INVALID_VALUE) { + if (!p_node->spec_const) { goto CONSTANT_RESULT; } - SpvReflectSpecializationConstant* p_constant; - res = GetSpecContantById(p_module, p_node->decorations.specialization_constant.value, &p_constant); - if (res != SPV_REFLECT_RESULT_SUCCESS) return res; - result->type = p_constant->type; - result->data.numeric.scalar = p_constant->current_value; + result->data.numeric.scalar = p_node->spec_const->current_value; } - return SPV_REFLECT_RESULT_SUCCESS; + break; case SpvOpSpecConstantComposite: { // only support compositing vector types for now... // vectors are needed for spv compiled to WorkgroupSize builtin // in expressing actual localsize - result->type = FindType(p_module, p_node->result_type_id); - if (!result->type) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; + // compositing types if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + goto CLEANUP; } uint32_t vec_size = 1; // should always have, since scalars do not need composite @@ -5811,49 +6015,48 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint } // check instruction size if (p_node->word_count != 3 + vec_size) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + goto CLEANUP; } for (uint32_t i = 0; i < vec_size; ++i) { - SpvReflectValue operandi = {0}; - GET_OPERAND(p_module, p_node, 3 + i, &operandi, maxRecursion); + SpvReflectValue* operandi = NULL; + GET_OPERAND(p_eval, p_node, 3 + i, operandi, res, CLEANUP); // check type compatibility - if (operandi.type && (operandi.type->type_flags & SCALAR_DISALLOWED_FLAGS)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + if (operandi->type->type_flags & SCALAR_DISALLOWED_FLAGS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } - if ((!operandi.type && !(result->type->type_flags& SPV_REFLECT_TYPE_FLAG_BOOL)) - ||(operandi.type && ((operandi.type->type_flags & SCALAR_TYPE_FLAGS) != (result->type->type_flags & SCALAR_TYPE_FLAGS)))) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - result->data.numeric.vector.value[i] = operandi.data.numeric.scalar; + result->data.numeric.vector.value[i] = operandi->data.numeric.scalar; } } - return SPV_REFLECT_RESULT_SUCCESS; + break; case SpvOpSpecConstantOp: { // operation has result type id, thus must be typed - result->type = FindType(p_module, p_node->result_type_id); - if (!result->type) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; // only vector and scalar types of int/bool/float types implemented // only OpSelect, OpUndef and access chain instructions can work with non-vector or scalar types // they are not currently supported... (likely never will) if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + goto CLEANUP; } // evaluate op uint32_t spec_op; - CHECKED_READU32(p_parser, p_node->word_offset + 3, spec_op); + EVAL_CHECKED_READU32(p_eval, p_node->word_offset + 3, spec_op, res, CLEANUP); switch (spec_op) { default: - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + goto CLEANUP; case SpvOpUndef: // write undefined value to result... { CHECK_INSTRUCTION_SIZE(p_node, 4) // all types allowed except void if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VOID) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { for (uint32_t i = 0; i < result->type->traits.numeric.vector.component_count; ++i) { @@ -5864,7 +6067,7 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint result->data.numeric.scalar.undefined_value = 1; } } - return SPV_REFLECT_RESULT_SUCCESS; + break; case SpvOpSConvert: // sign extend or truncate integers. // result is scalar or vector integer type. @@ -5873,33 +6076,38 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint CHECK_INSTRUCTION_SIZE(p_node, 5) // check result type - CHECK_IS_INTEGER_TYPE(result) - CHECK_VECTOR_OR_SCALAR_TYPE(result) + CHECK_IS_INTEGER_TYPE(result, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(result, res, CLEANUP) // get operand - SpvReflectValue operand1 = {0}; - GET_OPERAND(p_module, p_node, 4, &operand1, maxRecursion) - CHECK_IS_INTEGER_TYPE(&operand1) - CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) + SpvReflectValue* operand1 = NULL; + GET_OPERAND(p_eval, p_node, 4, operand1, res, CLEANUP) + CHECK_IS_INTEGER_TYPE(operand1, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) // operand must be signed - if (!operand1.type->traits.numeric.scalar.signedness) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + if (!operand1->type->traits.numeric.scalar.signedness) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } // vector size must match uint32_t vec_size = 1; - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, result, &operand1) + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, result, operand1, res, CLEANUP) // now do the job for (uint32_t i = 0; i < vec_size; ++i) { - result->data.numeric.vector.value[i].undefined_value = operand1.data.numeric.vector.value[i].undefined_value; - switch (operand1.type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + result->data.numeric.vector.value[i].undefined_value = operand1->data.numeric.vector.value[i].undefined_value; + switch (operand1->type->traits.numeric.scalar.width) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; case 32: { - int32_t data = operand1.data.numeric.vector.value[i].value.sint32_value; + int32_t data = operand1->data.numeric.vector.value[i].value.sint32_value; switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; case 32: result->data.numeric.vector.value[i].value.sint32_value = data; break; @@ -5911,9 +6119,11 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint break; case 64: { - int64_t data = operand1.data.numeric.vector.value[i].value.sint64_value; + int64_t data = operand1->data.numeric.vector.value[i].value.sint64_value; switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; case 32: result->data.numeric.vector.value[i].value.sint32_value = (int32_t)data; break; @@ -5926,7 +6136,7 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint } } } - return SPV_REFLECT_RESULT_SUCCESS; + break; case SpvOpUConvert: // zero extend or truncate integers. // result is scalar or vector integer type. @@ -5935,33 +6145,38 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint CHECK_INSTRUCTION_SIZE(p_node, 5) // check result type - CHECK_IS_INTEGER_TYPE(result) - CHECK_VECTOR_OR_SCALAR_TYPE(result) + CHECK_IS_INTEGER_TYPE(result, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(result, res, CLEANUP) // get operand - SpvReflectValue operand1 = {0}; - GET_OPERAND(p_module, p_node, 4, &operand1, maxRecursion) - CHECK_IS_INTEGER_TYPE(&operand1) - CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) + SpvReflectValue* operand1 = NULL; + GET_OPERAND(p_eval, p_node, 4, operand1, res, CLEANUP) + CHECK_IS_INTEGER_TYPE(operand1, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) // operand must not be signed - if (operand1.type->traits.numeric.scalar.signedness) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + if (operand1->type->traits.numeric.scalar.signedness) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } // vector size must match uint32_t vec_size = 1; - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, result, &operand1) + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, result, operand1, res, CLEANUP) // now do the job for (uint32_t i = 0; i < vec_size; ++i) { - result->data.numeric.vector.value[i].undefined_value = operand1.data.numeric.vector.value[i].undefined_value; - switch (operand1.type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + result->data.numeric.vector.value[i].undefined_value = operand1->data.numeric.vector.value[i].undefined_value; + switch (operand1->type->traits.numeric.scalar.width) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; case 32: { - uint32_t data = operand1.data.numeric.vector.value[i].value.uint32_bool_value; + uint32_t data = operand1->data.numeric.vector.value[i].value.uint32_bool_value; switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; case 32: result->data.numeric.vector.value[i].value.uint32_bool_value = data; break; @@ -5973,9 +6188,11 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint break; case 64: { - uint64_t data = operand1.data.numeric.vector.value[i].value.uint64_value; + uint64_t data = operand1->data.numeric.vector.value[i].value.uint64_value; switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; case 32: result->data.numeric.vector.value[i].value.uint32_bool_value = (uint32_t)data; break; @@ -5988,7 +6205,7 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint } } } - return SPV_REFLECT_RESULT_SUCCESS; + break; case SpvOpFConvert: // convert of floating point integer to any integer of different width. // just 32 and 64 bit for now... @@ -5996,93 +6213,105 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint CHECK_INSTRUCTION_SIZE(p_node, 5) // check result type - CHECK_IS_FLOAT_TYPE(result) - CHECK_VECTOR_OR_SCALAR_TYPE(result) + CHECK_IS_FLOAT_TYPE(result, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(result, res, CLEANUP) // get operand - SpvReflectValue operand1 = {0}; - GET_OPERAND(p_module, p_node, 4, &operand1, maxRecursion) + SpvReflectValue* operand1 = NULL; + GET_OPERAND(p_eval, p_node, 4, operand1, res, CLEANUP) // check type here, remember undefined value and booleans with type == null - CHECK_IS_FLOAT_TYPE(&operand1) - CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) + CHECK_IS_FLOAT_TYPE(operand1, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) // vector size must match uint32_t vec_size = 1; - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, result, &operand1) + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, result, operand1, res, CLEANUP) // now do the job for (uint32_t i = 0; i < vec_size; ++i) { - result->data.numeric.vector.value[i].undefined_value = operand1.data.numeric.vector.value[i].undefined_value; - switch (operand1.type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + result->data.numeric.vector.value[i].undefined_value = operand1->data.numeric.vector.value[i].undefined_value; + switch (operand1->type->traits.numeric.scalar.width) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; case 32: // convert int32 to generic integer type switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; case 32: - result->data.numeric.vector.value[i].value.float32_value = operand1.data.numeric.vector.value[i].value.float32_value; + result->data.numeric.vector.value[i].value.float32_value = operand1->data.numeric.vector.value[i].value.float32_value; break; case 64: - result->data.numeric.vector.value[i].value.float64_value = (double)operand1.data.numeric.vector.value[i].value.float32_value; + result->data.numeric.vector.value[i].value.float64_value = (double)operand1->data.numeric.vector.value[i].value.float32_value; break; } break; case 64: // convert int64 to generic integer type switch (result->type->traits.numeric.scalar.width) { - default: return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; case 32: - result->data.numeric.vector.value[i].value.float32_value = (float)operand1.data.numeric.vector.value[i].value.float64_value; + result->data.numeric.vector.value[i].value.float32_value = (float)operand1->data.numeric.vector.value[i].value.float64_value; break; case 64: - result->data.numeric.vector.value[i].value.float64_value = operand1.data.numeric.vector.value[i].value.float64_value; + result->data.numeric.vector.value[i].value.float64_value = operand1->data.numeric.vector.value[i].value.float64_value; break; } } } } - return SPV_REFLECT_RESULT_SUCCESS; + break; case SpvOpSNegate: #undef SIMPLE_UNARY_OP_32_BIT_HOOK #undef SIMPLE_UNARY_OP_64_BIT_HOOK #define SIMPLE_UNARY_OP_32_BIT_HOOK {data = -data;} #define SIMPLE_UNARY_OP_64_BIT_HOOK {data = -data;} - DO_SIMPLE_UNARY_INTEGER_OPERATION(result, p_module, p_node, maxRecursion) + DO_SIMPLE_UNARY_INTEGER_OPERATION(result, p_eval, p_node, res, CLEANUP) #undef SIMPLE_UNARY_OP_32_BIT_HOOK #undef SIMPLE_UNARY_OP_64_BIT_HOOK #define SIMPLE_UNARY_OP_32_BIT_HOOK #define SIMPLE_UNARY_OP_64_BIT_HOOK + break; case SpvOpNot: // bitwise not of every component in op1, store into same width result. #undef SIMPLE_UNARY_OP_32_BIT_HOOK #undef SIMPLE_UNARY_OP_64_BIT_HOOK #define SIMPLE_UNARY_OP_32_BIT_HOOK data ^= 0xffffffff; #define SIMPLE_UNARY_OP_64_BIT_HOOK data ^= 0xffffffffffffffff; - DO_SIMPLE_UNARY_INTEGER_OPERATION(result, p_module, p_node, maxRecursion) + DO_SIMPLE_UNARY_INTEGER_OPERATION(result, p_eval, p_node, res, CLEANUP) #undef SIMPLE_UNARY_OP_32_BIT_HOOK #undef SIMPLE_UNARY_OP_64_BIT_HOOK #define SIMPLE_UNARY_OP_32_BIT_HOOK #define SIMPLE_UNARY_OP_64_BIT_HOOK + break; case SpvOpIAdd: // integer add. // subtraction result is the same for 2-compliment - DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, +, maxRecursion) + DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_eval, p_node, +, res, CLEANUP) + break; case SpvOpISub: // integer subtract. // subtraction result is the same for 2-compliment - DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, -, maxRecursion) + DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_eval, p_node, -, res, CLEANUP) + break; case SpvOpIMul: // integer multiply... // imul instruction on x86, signed and unsigned have no difference in result // except for how they overflow. - DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, *, maxRecursion) + DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_eval, p_node, *, res, CLEANUP) + break; case SpvOpUDiv: // unsigned divide // All operand must be same unsigned integer scalar or vector type. // x86 div instruction // emits undefined value if divide by zero - DO_UNSIGNED_INTEGER_DIVISION(result, p_module, p_node, /, maxRecursion) + DO_UNSIGNED_INTEGER_DIVISION(result, p_eval, p_node, /, res, CLEANUP) + break; case SpvOpSDiv: // signed divide // x86 idiv instruction @@ -6092,22 +6321,24 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint #undef SIMPLE_BINARY_OP_32_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ - result->data.numeric.vector.value[i].undefined_value = 1; \ + result->data.numeric.vector.value[i].undefined_value = 1; \ } #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_64_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ - result->data.numeric.vector.value[i].undefined_value = 1; \ + result->data.numeric.vector.value[i].undefined_value = 1; \ } - DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, /, maxRecursion) + DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_eval, p_node, /, res, CLEANUP) #undef SIMPLE_BINARY_OP_32_BIT_HOOK #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK #define SIMPLE_BINARY_OP_64_BIT_HOOK + break; case SpvOpUMod: // unsigned modulo // all types must be same unsigned integer scalar or vector type. - DO_UNSIGNED_INTEGER_DIVISION(result, p_module, p_node, %, maxRecursion) + DO_UNSIGNED_INTEGER_DIVISION(result, p_eval, p_node, %, res, CLEANUP) + break; case SpvOpSRem: // just the result of % operator. #undef SIMPLE_BINARY_OP_32_BIT_HOOK @@ -6120,11 +6351,12 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ result->data.numeric.vector.value[i].undefined_value = 1; \ } - DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, %, maxRecursion) + DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_eval, p_node, %, res, CLEANUP) #undef SIMPLE_BINARY_OP_32_BIT_HOOK #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK #define SIMPLE_BINARY_OP_64_BIT_HOOK + break; case SpvOpSMod: // not result of % operator, need adjusting with dividend... #undef SIMPLE_BINARY_OP_32_BIT_HOOK @@ -6155,14 +6387,16 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint data += data2; \ } \ } - DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, %, maxRecursion) + DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_eval, p_node, %, res, CLEANUP) #undef SIMPLE_BINARY_OP_32_BIT_HOOK #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK #define SIMPLE_BINARY_OP_64_BIT_HOOK + break; case SpvOpShiftRightLogical: // zero fill right shift. Just >> in c - DO_SHIFT_OPERATION(result, p_module, p_node, >>, maxRecursion) + DO_SHIFT_OPERATION(result, p_eval, p_node, >>, res, CLEANUP) + break; case SpvOpShiftRightArithmetic: // fill with sign of original number. #undef SHIFT_OP_32_BIT_HOOK_PRE @@ -6181,7 +6415,7 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint uint64_t fill = 0xffffffffffffffff << (64 - shift_num); \ data |= fill; \ } - DO_SHIFT_OPERATION(result, p_module, p_node, >> , maxRecursion) + DO_SHIFT_OPERATION(result, p_eval, p_node, >> , res, CLEANUP) #undef SHIFT_OP_32_BIT_HOOK_PRE #undef SHIFT_OP_64_BIT_HOOK_PRE #undef SHIFT_OP_32_BIT_HOOK_POST @@ -6190,44 +6424,53 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint #define SHIFT_OP_64_BIT_HOOK_PRE #define SHIFT_OP_32_BIT_HOOK_POST #define SHIFT_OP_64_BIT_HOOK_POST + break; case SpvOpShiftLeftLogical: // zero fill left shift. Just << in c - DO_SHIFT_OPERATION(result, p_module, p_node, << , maxRecursion) + DO_SHIFT_OPERATION(result, p_eval, p_node, << , res, CLEANUP) + break; case SpvOpBitwiseOr: - DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, |, maxRecursion) + DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_eval, p_node, |, res, CLEANUP) + break; case SpvOpBitwiseXor: - DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, ^ , maxRecursion) + DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_eval, p_node, ^ , res, CLEANUP) + break; case SpvOpBitwiseAnd: - DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_module, p_node, & , maxRecursion) + DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_eval, p_node, & , res, CLEANUP) + break; - // Do not support compostion of vectors for now... case SpvOpVectorShuffle: { /* check result type*/ - CHECK_IS_INTEGER_TYPE(result) - CHECK_VECTOR_OR_SCALAR_TYPE(result) + CHECK_IS_INTEGER_TYPE(result, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(result, res, CLEANUP) if (!(result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } - SpvReflectValue operand1 = {0}; - GET_OPERAND((p_module), (p_node), 4, &operand1, maxRecursion) - CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) - if (!(operand1.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + SpvReflectValue* operand1 = NULL; + GET_OPERAND((p_eval), (p_node), 4, operand1, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) + if (!(operand1->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } - if (operand1.type->component_type_id != result->type->component_type_id) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + if (operand1->type->component_type_id != result->type->component_type_id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } // cannot skip if type comes with result... - SpvReflectValue operand2 = {0}; - GET_OPERAND((p_module), (p_node), 5, &operand2, maxRecursion) - if (!(operand2.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + SpvReflectValue* operand2 = NULL; + GET_OPERAND((p_eval), (p_node), 5, operand2, res, CLEANUP) + if (!(operand2->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } - if (operand2.type->component_type_id != result->type->component_type_id) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + if (operand2->type->component_type_id != result->type->component_type_id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } // instruction size must be: @@ -6237,156 +6480,170 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint // now do the job... for (uint32_t i = 0; i < result->type->traits.numeric.vector.component_count; ++i) { uint32_t mapped_component; - CHECKED_READU32(p_parser, p_node->word_offset + 6 + i, mapped_component) + EVAL_CHECKED_READU32(p_eval, p_node->word_offset + 6 + i, mapped_component, res, CLEANUP) if (mapped_component == 0xFFFFFFFF) { result->data.numeric.vector.value[i].undefined_value = 1; } - else if (mapped_component >= operand1.type->traits.numeric.vector.component_count + operand2.type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + else if (mapped_component >= operand1->type->traits.numeric.vector.component_count + operand2->type->traits.numeric.vector.component_count) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + goto CLEANUP; } - else if (mapped_component < operand1.type->traits.numeric.vector.component_count) { - result->data.numeric.vector.value[i] = operand1.data.numeric.vector.value[mapped_component]; + else if (mapped_component < operand1->type->traits.numeric.vector.component_count) { + result->data.numeric.vector.value[i] = operand1->data.numeric.vector.value[mapped_component]; } else { - result->data.numeric.vector.value[i] = operand2.data.numeric.vector.value[mapped_component - operand1.type->traits.numeric.vector.component_count]; + result->data.numeric.vector.value[i] = operand2->data.numeric.vector.value[mapped_component - operand1->type->traits.numeric.vector.component_count]; } } - return SPV_REFLECT_RESULT_SUCCESS; } + break; // only support vector types for now... case SpvOpCompositeExtract: { // check composite allowed flags if (result->type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } // need to travers the composite tree down to last operand. // currently only support vector composite type. - SpvReflectValue operand1 = {0}; - GET_OPERAND((p_module), (p_node), 4, &operand1, maxRecursion) - if (operand1.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + SpvReflectValue* operand1 = NULL; + GET_OPERAND((p_eval), (p_node), 4, operand1, res, CLEANUP) + if (operand1->type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } uint32_t cur_offset = 5; - SpvReflectValueData* current_data = &operand1.data; - SpvReflectTypeDescription* current_type = operand1.type; + SpvReflectValueData* current_data = &operand1->data; + SpvReflectTypeDescription* current_type = operand1->type; for (; cur_offset < p_node->word_count; ++cur_offset) { uint32_t member_index; - CHECKED_READU32(p_parser, p_node->word_offset+cur_offset, member_index); - SpvReflectResult err = GetMemberByIndex(p_module, current_data, current_type, member_index, ¤t_data, ¤t_type); - if (err != SPV_REFLECT_RESULT_SUCCESS) { - return err; + EVAL_CHECKED_READU32(p_eval, p_node->word_offset+cur_offset, member_index, res, CLEANUP); + res = GetMemberByIndex(p_eval->member_type_finder, current_data, current_type, member_index, ¤t_data, ¤t_type); + if (res != SPV_REFLECT_RESULT_SUCCESS) { + goto CLEANUP; } } if (current_type->id != result->type->id) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } - SpvReflectResult err = CopyValueData(p_module, current_type, &result->data, current_data); - if (err != SPV_REFLECT_RESULT_SUCCESS) { - return err; + res = CopyValueData(current_type, &result->data, current_data); + if (res != SPV_REFLECT_RESULT_SUCCESS) { + goto CLEANUP; } } - return SPV_REFLECT_RESULT_SUCCESS; + break; case SpvOpCompositeInsert: { if (result->type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } - SpvReflectValue operand2 = {0}; - GET_OPERAND((p_module), (p_node), 5, &operand2, maxRecursion) - if (operand2.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - if (operand2.type) { - if (operand2.type->id != result->type->id) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + SpvReflectValue* operand2 = NULL; + GET_OPERAND((p_eval), (p_node), 5, operand2, res, CLEANUP) + if (operand2->type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + if (operand2->type) { + if (operand2->type->id != result->type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } } else { if (result->type->type_flags != SPV_REFLECT_TYPE_FLAG_BOOL) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } } - result->data = operand2.data; + result->data = operand2->data; - SpvReflectValue operand1 = {0}; - GET_OPERAND((p_module), (p_node), 4, &operand1, maxRecursion) + SpvReflectValue* operand1 = NULL; + GET_OPERAND((p_eval), (p_node), 4, operand1, res, CLEANUP) uint32_t cur_offset = 6; SpvReflectValueData* current_data = &result->data; SpvReflectTypeDescription* current_type = result->type; for (; cur_offset < p_node->word_count; ++cur_offset) { uint32_t member_index; - CHECKED_READU32(p_parser, p_node->word_offset + cur_offset, member_index); - SpvReflectResult err = GetMemberByIndex(p_module, current_data, current_type, member_index, ¤t_data, ¤t_type); - if (err != SPV_REFLECT_RESULT_SUCCESS) { - return err; + EVAL_CHECKED_READU32(p_eval, p_node->word_offset + cur_offset, member_index, res, CLEANUP); + res = GetMemberByIndex(p_eval->member_type_finder, current_data, current_type, member_index, ¤t_data, ¤t_type); + if (res != SPV_REFLECT_RESULT_SUCCESS) { + goto CLEANUP; } } if (!current_type) { - if (operand1.type && (operand1.type->type_flags != SPV_REFLECT_TYPE_FLAG_BOOL)) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + if (operand1->type && (operand1->type->type_flags != SPV_REFLECT_TYPE_FLAG_BOOL)) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } } else { - if (operand1.type) { - if (current_type->id != operand1.type->id) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + if (operand1->type) { + if (current_type->id != operand1->type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } } else if (current_type->type_flags != SPV_REFLECT_TYPE_FLAG_BOOL) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } } - SpvReflectResult err = CopyValueData(p_module, current_type, current_data, &operand1.data); - if (err != SPV_REFLECT_RESULT_SUCCESS) { - return err; + res = CopyValueData(current_type, current_data, &operand1->data); + if (res != SPV_REFLECT_RESULT_SUCCESS) { + goto CLEANUP; } } - return SPV_REFLECT_RESULT_SUCCESS; + break; case SpvOpLogicalOr: - DO_BINARY_BOOLEAN_LOGICAL_OPERATION(result, p_module, p_node, ||, maxRecursion) + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(result, p_eval, p_node, ||, res, CLEANUP) + break; case SpvOpLogicalAnd: - DO_BINARY_BOOLEAN_LOGICAL_OPERATION(result, p_module, p_node, && , maxRecursion) - + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(result, p_eval, p_node, && , res, CLEANUP) + break; case SpvOpLogicalNot: { CHECK_INSTRUCTION_SIZE(p_node, 5) /* check result type */ - CHECK_IS_BOOLEAN_TYPE(result) - CHECK_VECTOR_OR_SCALAR_TYPE(result) + CHECK_IS_BOOLEAN_TYPE(result, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(result, res, CLEANUP) /* get operand */ - SpvReflectValue operand1 = {0}; - GET_OPERAND((p_module), (p_node), 4, &operand1, maxRecursion) - CHECK_IS_BOOLEAN_TYPE(&operand1) - CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) + SpvReflectValue* operand1 = NULL; + GET_OPERAND((p_eval), (p_node), 4, operand1, res, CLEANUP) + CHECK_IS_BOOLEAN_TYPE(operand1, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) /* vectors must be of same size */ uint32_t vec_size = 1; - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, result, &operand1) + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, result, operand1, res, CLEANUP) for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1.data.numeric.vector.value[i].undefined_value) { + if (operand1->data.numeric.vector.value[i].undefined_value) { result->data.numeric.vector.value[i].undefined_value = 1; } /* write to correct offset */ - result->data.numeric.vector.value[i].value.uint32_bool_value = !operand1.data.numeric.vector.value[i].value.uint32_bool_value; + result->data.numeric.vector.value[i].value.uint32_bool_value = !operand1->data.numeric.vector.value[i].value.uint32_bool_value; } } - return SPV_REFLECT_RESULT_SUCCESS; + break; case SpvOpLogicalEqual: - DO_BINARY_BOOLEAN_LOGICAL_OPERATION(result, p_module, p_node, ==, maxRecursion) + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(result, p_eval, p_node, ==, res, CLEANUP) + break; case SpvOpLogicalNotEqual: - DO_BINARY_BOOLEAN_LOGICAL_OPERATION(result, p_module, p_node, != , maxRecursion) + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(result, p_eval, p_node, != , res, CLEANUP) + break; case SpvOpSelect: // same as c/cpp code: a ? b : c; // should allow composite types if not for spec-constant since 1.4 @@ -6395,50 +6652,54 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint /* check result type, different from other instance since it should support composite type if not for spec constant */ if (result->type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } - SpvReflectValue operand1 = {0}; - GET_OPERAND((p_module), (p_node), 4, &operand1, maxRecursion) - CHECK_IS_BOOLEAN_TYPE(&operand1) - CHECK_VECTOR_OR_SCALAR_TYPE(&operand1) + SpvReflectValue* operand1 = NULL; + GET_OPERAND((p_eval), (p_node), 4, operand1, res, CLEANUP) + CHECK_IS_BOOLEAN_TYPE(operand1, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) // cannot skip if type comes with result... - SpvReflectValue operand2 = {0}; - GET_OPERAND((p_module), (p_node), 5, &operand2, maxRecursion) - if (operand2.type->id != result->type->id) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + SpvReflectValue* operand2 = NULL; + GET_OPERAND((p_eval), (p_node), 5, operand2, res, CLEANUP) + if (operand2->type->id != result->type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } - SpvReflectValue operand3 = {0}; - GET_OPERAND((p_module), (p_node), 6, &operand3, maxRecursion) - if (operand3.type->id != result->type->id) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + SpvReflectValue* operand3 = NULL; + GET_OPERAND((p_eval), (p_node), 6, operand3, res, CLEANUP) + if (operand3->type->id != result->type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } uint32_t vec_size = 1; // result can be vector if operand is scalar. - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, &operand1, result); + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, operand1, result, res, CLEANUP); if (vec_size != 1) { if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1.data.numeric.vector.value[i].undefined_value) { + if (operand1->data.numeric.vector.value[i].undefined_value) { result->data.numeric.vector.value[i].undefined_value = 1; } - if (operand1.data.numeric.vector.value[i].value.uint32_bool_value) { - if (operand2.data.numeric.vector.value[i].undefined_value) { + if (operand1->data.numeric.vector.value[i].value.uint32_bool_value) { + if (operand2->data.numeric.vector.value[i].undefined_value) { result->data.numeric.vector.value[i].undefined_value = 1; } - result->data.numeric.vector.value[i].value = operand2.data.numeric.vector.value[i].value; + result->data.numeric.vector.value[i].value = operand2->data.numeric.vector.value[i].value; } else { - if (operand3.data.numeric.vector.value[i].undefined_value) { + if (operand3->data.numeric.vector.value[i].undefined_value) { result->data.numeric.vector.value[i].undefined_value = 1; } - result->data.numeric.vector.value[i].value = operand3.data.numeric.vector.value[i].value; + result->data.numeric.vector.value[i].value = operand3->data.numeric.vector.value[i].value; } } } @@ -6447,18 +6708,19 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint // we can't deal with other types for now... if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + goto CLEANUP; } - if (operand1.data.numeric.scalar.value.uint32_bool_value) { + if (operand1->data.numeric.scalar.value.uint32_bool_value) { // need deep copy if complex - *result = operand2; + *result = *operand2; } else { // need deep copy if complex - *result = operand3; + *result = *operand3; } - if (operand1.data.numeric.vector.value[0].undefined_value) { + if (operand1->data.numeric.vector.value[0].undefined_value) { // we shouldn't care about content here... for (uint32_t i = 0; i < SPV_REFLECT_MAX_VECTOR_DIMS; ++i) { result->data.numeric.vector.value[i].undefined_value = 1; @@ -6466,31 +6728,41 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint } } } - return SPV_REFLECT_RESULT_SUCCESS; + break; case SpvOpIEqual: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_module, p_node, ==, maxRecursion) + DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, ==, res, CLEANUP) + break; case SpvOpINotEqual: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_module, p_node, != , maxRecursion) + DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, != , res, CLEANUP) + break; case SpvOpULessThan: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_module, p_node, < , maxRecursion) + DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, < , res, CLEANUP) + break; case SpvOpSLessThan: - DO_BINARY_SINTEGER_LOGICAL_OPERATION(result, p_module, p_node, < , maxRecursion) + DO_BINARY_SINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, < , res, CLEANUP) + break; case SpvOpUGreaterThan: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_module, p_node, > , maxRecursion) + DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, > , res, CLEANUP) + break; case SpvOpSGreaterThan: - DO_BINARY_SINTEGER_LOGICAL_OPERATION(result, p_module, p_node, > , maxRecursion) + DO_BINARY_SINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, > , res, CLEANUP) + break; case SpvOpULessThanEqual: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_module, p_node, <= , maxRecursion) + DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, <= , res, CLEANUP) + break; case SpvOpSLessThanEqual: - DO_BINARY_SINTEGER_LOGICAL_OPERATION(result, p_module, p_node, <= , maxRecursion) + DO_BINARY_SINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, <= , res, CLEANUP) + break; case SpvOpUGreaterThanEqual: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_module, p_node, >= , maxRecursion) + DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, >= , res, CLEANUP) + break; case SpvOpSGreaterThanEqual: - DO_BINARY_SINTEGER_LOGICAL_OPERATION(result, p_module, p_node, >= , maxRecursion) + DO_BINARY_SINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, >= , res, CLEANUP) + break; // check shader capability... vulkan should assume this... case SpvOpQuantizeToF16: - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; break; // check kernel capability... vulkan have none currently... @@ -6503,26 +6775,33 @@ SpvReflectResult EvaluateResultImpl(const SpvReflectShaderModule* p_module, uint case SpvOpFRem: case SpvOpFMod: case SpvOpAccessChain: case SpvOpInBoundsAccessChain: case SpvOpPtrAccessChain: case SpvOpInBoundsPtrAccessChain: - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; break; - } } - + break; + } + CLEANUP: + if (res != SPV_REFLECT_RESULT_SUCCESS) { + p_node->evaluation_state = SPV_REFLECT_EVALUATION_STATE_FAILED; } + else { + p_node->evaluation_state = SPV_REFLECT_EVALUATION_STATE_DONE; + } + return res; } -SpvReflectResult EvaluateResult(const SpvReflectShaderModule* p_module, uint32_t result_id, SpvReflectValue* result) +SpvReflectResult EvaluateResult(SpvReflectShaderModule* p_module, uint32_t result_id, const SpvReflectValue** result) { if (!result || !p_module) { return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; } - if((p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_SPEC_CONSTANT)==0){ + if((p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT)==0){ return SPV_REFLECT_RESULT_ERROR_PARSE_FAILED; } // compute at most 100 instruction levels, maybe defining somewhere is better. - return EvaluateResultImpl(p_module, result_id, result, 100); + return EvaluateResultImpl(p_module->_internal->evaluator, result_id, result); } diff --git a/spirv_reflect.h b/spirv_reflect.h index 314ebc1b..bc424515 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -96,14 +96,21 @@ SPV_REFLECT_MODULE_FLAG_NO_COPY - Disables copying of SPIR-V code This is flag is intended for cases where the memory overhead of storing the copied SPIR-V is undesirable. -SPV_REFLECT_MODULE_FLAG_EVALUATE_SPEC_CONSTANT - Keeps the parser - as long as the shader module is in lifetime. Needed for evaluating - specialization ops after specifying values. +SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT - copies constant + instructions for use with later evaluation. + +SPV_REFLECT_MODULE_FLAG_EVALUATE_NO_COPY - use p_code for later + evaluation. User need to make sure not to free memory. Code + pointed to need to be valid upon re-evaluation. Re-evaluation + MAY happen after changing any spec constant, and when a op is + evaluated for the first time. (behavior may be changed to only + when related constants are changed) */ typedef enum SpvReflectModuleFlagBits { SPV_REFLECT_MODULE_FLAG_NONE = 0x00000000, SPV_REFLECT_MODULE_FLAG_NO_COPY = 0x00000001, - SPV_REFLECT_MODULE_FLAG_EVALUATE_SPEC_CONSTANT = 0x00000002 + SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT = 0x00000002, + SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT_NO_COPY = 0x00000004 } SpvReflectModuleFlagBits; typedef uint32_t SpvReflectModuleFlags; @@ -375,17 +382,19 @@ typedef struct SpvReflectVectorValueData { // this struct is not meant to be created on user stack, // instead in a internal dictionary and give user const ptr to read. typedef union SpvReflectValueNumericData { - SpvReflectScalarValueData scalar; - SpvReflectVectorValueData vector; + SpvReflectScalarValueData scalar; + SpvReflectVectorValueData vector; } SpvReflectValueNumericData; typedef union SpvReflectValueData { - SpvReflectValueNumericData numeric; + SpvReflectValueNumericData numeric; } SpvReflectValueData; typedef struct SpvReflectValue { - SpvReflectTypeDescription* type; - SpvReflectValueData data; + // never null in valid spirv + // means result type id + SpvReflectTypeDescription* type; + SpvReflectValueData data; }SpvReflectValue; typedef struct SpvReflectSpecializationConstant { @@ -535,6 +544,8 @@ typedef struct SpvReflectEntryPoint { typedef struct SpvReflectPrvParser SpvReflectPrvParser; +typedef struct SpvReflectPrvEvaluation SpvReflectPrvEvaluation; + /*! @struct SpvReflectShaderModule */ @@ -574,7 +585,7 @@ typedef struct SpvReflectShaderModule { size_t type_description_count; SpvReflectTypeDescription* type_descriptions; - SpvReflectPrvParser* parser; + SpvReflectPrvEvaluation* evaluator; } * _internal; } SpvReflectShaderModule; @@ -1530,7 +1541,7 @@ const char* spvReflectBlockVariableTypeName( const SpvReflectBlockVariable* p_var ); -SpvReflectResult EvaluateResult(const SpvReflectShaderModule* p_module, uint32_t result_id, SpvReflectValue* result); +SpvReflectResult EvaluateResult(SpvReflectShaderModule* p_module, uint32_t result_id, const SpvReflectValue** result); #if defined(__cplusplus) }; @@ -1638,9 +1649,9 @@ class ShaderModule { SpvReflectResult ChangeInputVariableLocation(const SpvReflectInterfaceVariable* p_input_variable, uint32_t new_location); SpvReflectResult ChangeOutputVariableLocation(const SpvReflectInterfaceVariable* p_output_variable, uint32_t new_location); - SpvReflectResult EvaluateResult(uint32_t result_id, SpvReflectValue& result) const + SpvReflectResult EvaluateResult(uint32_t result_id, const SpvReflectValue** result) { - return ::EvaluateResult(&m_module, result_id, &result); + return ::EvaluateResult(&m_module, result_id, result); } private: From ce8551e6502303f5162290728dcbfdc51bd69641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:37:31 +0800 Subject: [PATCH 12/44] Fix wrong type flag --- spirv_reflect.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index 9f110451..cc4e6a64 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -881,20 +881,10 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) case SpvOpConstant: case SpvOpConstantComposite: case SpvOpConstantSampler: - case SpvOpConstantNull: { - CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id); - CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id); - } - break; - + case SpvOpConstantNull: case SpvOpSpecConstantTrue: case SpvOpSpecConstantFalse: - case SpvOpSpecConstant: { - CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id); - CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id); - p_node->is_type = true; - } - break; + case SpvOpSpecConstant: case SpvOpSpecConstantComposite: case SpvOpSpecConstantOp: { CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id); @@ -4116,6 +4106,7 @@ static SpvReflectResult CreateShaderModule( } DestroyParser(&parser); + return result; } From 87440b4b19abb0e69cabe5dab748591a5c291edc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Tue, 2 Aug 2022 00:40:56 +0800 Subject: [PATCH 13/44] Sorting up api... --- spirv_reflect.c | 200 ++++++++++++++++++++++++++++++++++++------------ spirv_reflect.h | 82 ++++++++++++++++++-- 2 files changed, 227 insertions(+), 55 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index cc4e6a64..a7092b01 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -237,12 +237,12 @@ typedef struct SpvReflectPrvEvaluationNode { SpvReflectEvaluationState evaluation_state; SpvReflectValue value; - SpvReflectSpecializationConstant* spec_const; + uint32_t specId; } SpvReflectPrvEvaluationNode; // clang-format on // clang-format off -typedef struct SpvReflectPrvEvaluation { +typedef struct SpvReflectEvaluation { // original code if no-copy, else it's a copy of constant instructions size_t spirv_word_count; uint32_t* spirv_code; @@ -250,10 +250,13 @@ typedef struct SpvReflectPrvEvaluation { uint32_t node_count; SpvReflectPrvEvaluationNode* nodes; + // To flag dry run and tree traversal... + uint32_t flags; + // ohh I hope I could decouple this... But FindType uses this... // just a reference SpvReflectShaderModule* member_type_finder; -} SpvReflectPrvEvaluation; +} SpvReflectEvaluation; // clang-format on @@ -563,7 +566,7 @@ static SpvReflectPrvNode* FindNode( } static SpvReflectPrvEvaluationNode* FindEvaluationNode( - SpvReflectPrvEvaluation* p_eval, + SpvReflectEvaluation* p_eval, uint32_t result_id) { SpvReflectPrvEvaluationNode* p_node = NULL; @@ -577,6 +580,21 @@ static SpvReflectPrvEvaluationNode* FindEvaluationNode( return p_node; } +static SpvReflectPrvEvaluationNode* FindSpecIdNode( + SpvReflectEvaluation* p_eval, + uint32_t specid) +{ + SpvReflectPrvEvaluationNode* p_node = NULL; + for (size_t i = 0; i < p_eval->node_count; ++i) { + SpvReflectPrvEvaluationNode* p_elem = &(p_eval->nodes[i]); + if (p_elem->specId == specid) { + p_node = p_elem; + break; + } + } + return p_node; +} + static SpvReflectTypeDescription* FindType(const SpvReflectShaderModule* p_module, uint32_t type_id) { SpvReflectTypeDescription* p_type = NULL; @@ -3433,7 +3451,7 @@ static SpvReflectResult ParseExecutionModes( } static bool EvalCodeInRange( - const SpvReflectPrvEvaluation* p_eval, + const SpvReflectEvaluation* p_eval, uint32_t index) { bool in_range = false; @@ -3444,7 +3462,7 @@ static bool EvalCodeInRange( } static SpvReflectResult EvalReadU32( - const SpvReflectPrvEvaluation* p_eval, + const SpvReflectEvaluation* p_eval, uint32_t word_offset, uint32_t* p_value) { @@ -3477,7 +3495,7 @@ static SpvReflectResult EvalReadU32( #define COMPOSITE_DISALLOWED_FLAGS (~0 ^ COMPOSITE_TYPE_FLAGS) // getting constant also happens before evaluation is created. -static SpvReflectResult EvalGetScalarConstant(const SpvReflectPrvEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node) +static SpvReflectResult EvalGetScalarConstant(const SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node) { SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS; if(p_node->value.type->type_flags & SCALAR_DISALLOWED_FLAGS) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; @@ -3528,13 +3546,14 @@ static SpvReflectResult ParserGetScalarConstant(const SpvReflectShaderModule* p_ #define MODULE_EVALUATION_FLAGS (SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT | SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT_NO_COPY) -#define IS_CONSTANT_OP(op_code) \ +#define IS_CONSTANT_LITERAL_OP(op_code)\ (((op_code) == SpvOpSpecConstantTrue) || ((op_code) == SpvOpSpecConstantFalse) || ((op_code) == SpvOpSpecConstant) \ - || ((op_code) == SpvOpSpecConstantOp) || ((op_code) == SpvOpSpecConstantComposite) || ((op_code) == SpvOpConstant) \ - || ((op_code) == SpvOpConstantTrue) || ((op_code) == SpvOpConstantFalse) || ((op_code) == SpvOpConstantComposite) \ - || ((op_code) == SpvOpConstantNull) || ((op_code) == SpvOpConstantSampler) || ((op_code) == SpvOpConstantPipeStorage) \ - || ((op_code) == SpvOpSpecConstantCompositeContinuedINTEL) || ((op_code) == SpvOpConstantFunctionPointerINTEL) \ - || ((op_code) == SpvOpConstantCompositeContinuedINTEL)) + || ((op_code) == SpvOpConstantTrue) || ((op_code) == SpvOpConstantFalse) || ((op_code) == SpvOpConstant)) +#define IS_CONSTANT_OP(op_code) \ + (IS_CONSTANT_LITERAL_OP(op_code) || ((op_code) == SpvOpSpecConstantOp) || ((op_code) == SpvOpSpecConstantComposite) \ + || ((op_code) == SpvOpConstantComposite) || ((op_code) == SpvOpConstantNull) || ((op_code) == SpvOpConstantSampler) \ + || ((op_code) == SpvOpConstantPipeStorage) || ((op_code) == SpvOpSpecConstantCompositeContinuedINTEL)\ + || ((op_code) == SpvOpConstantFunctionPointerINTEL) || ((op_code) == SpvOpConstantCompositeContinuedINTEL)) // defined later.. static SpvReflectSpecializationConstant* GetSpecContantById(const SpvReflectShaderModule* p_module, uint32_t constant_id); @@ -3584,11 +3603,9 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars default: continue; case SpvOpSpecConstantTrue: { p_module->specialization_constants[index].default_value.value.uint32_bool_value = 1; - p_module->specialization_constants[index].current_value = p_module->specialization_constants[index].default_value; } break; case SpvOpSpecConstantFalse: { p_module->specialization_constants[index].default_value.value.uint32_bool_value = 0; - p_module->specialization_constants[index].current_value = p_module->specialization_constants[index].default_value; } break; case SpvOpSpecConstant: { SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS; @@ -3596,7 +3613,6 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars result = ParserGetScalarConstant(p_module, p_parser, p_node, &default_value, &p_module->specialization_constants[index].type); if (result != SPV_REFLECT_RESULT_SUCCESS) return result; p_module->specialization_constants[index].default_value = default_value; - p_module->specialization_constants[index].current_value = p_module->specialization_constants[index].default_value; } break; } // spec constant id cannot be the same, at least for valid values. (invalid value is just constant?) @@ -3616,7 +3632,7 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars // need to evaluate expr later on... if (p_module->_internal->module_flags & MODULE_EVALUATION_FLAGS) { - p_module->_internal->evaluator = (SpvReflectPrvEvaluation*)calloc(1, sizeof(SpvReflectPrvEvaluation)); + p_module->_internal->evaluator = (SpvReflectEvaluation*)calloc(1, sizeof(SpvReflectEvaluation)); // needed for FindType for constituent types p_module->_internal->evaluator->member_type_finder = p_module; p_module->_internal->evaluator->node_count = constant_instruction_num; @@ -3647,10 +3663,18 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; } p_module->_internal->evaluator->nodes[current_cinst].evaluation_state = SPV_REFLECT_EVALUATION_STATE_UNINITIALIZED; - p_module->_internal->evaluator->nodes[current_cinst].spec_const = NULL; - if (p_node->decorations.specialization_constant.value != INVALID_VALUE) { - p_module->_internal->evaluator->nodes[current_cinst].spec_const = GetSpecContantById(p_module, p_node->decorations.specialization_constant.value); + if (IS_CONSTANT_LITERAL_OP(p_node->op)) { + SpvReflectResult res = ParserGetScalarConstant(p_module, p_parser, p_node, + &p_module->_internal->evaluator->nodes[current_cinst].value.data.numeric.scalar, + &p_module->_internal->evaluator->nodes[current_cinst].value.type); + if (res == SPV_REFLECT_RESULT_SUCCESS) { + p_module->_internal->evaluator->nodes[current_cinst].evaluation_state = SPV_REFLECT_EVALUATION_STATE_DONE; + } + else { + p_module->_internal->evaluator->nodes[current_cinst].evaluation_state = SPV_REFLECT_EVALUATION_STATE_FAILED; + } } + p_module->_internal->evaluator->nodes[current_cinst].specId = p_node->decorations.specialization_constant.value; if (p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT_NO_COPY) { p_module->_internal->evaluator->nodes[current_cinst].word_offset = p_node->word_offset; } @@ -3667,7 +3691,7 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars return SPV_REFLECT_RESULT_SUCCESS; } -static void DestroyEvaluator(SpvReflectPrvEvaluation* evaluator, bool owns_code) +static void DestroyEvaluator(SpvReflectEvaluation* evaluator, bool owns_code) { SafeFree(evaluator->nodes); if (owns_code) { @@ -5939,7 +5963,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect // memcpy is required since c/c++ have strict aliasing rules // access to signed and unsigned versions of same width integer's // address does not violate strict aliasing rules -SpvReflectResult EvaluateResultImpl(SpvReflectPrvEvaluation* p_eval, uint32_t result_id, const SpvReflectValue** p_result) +SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t result_id, const SpvReflectValue** p_result) { SpvReflectResult res = SPV_REFLECT_RESULT_SUCCESS; SpvReflectPrvEvaluationNode* p_node = FindEvaluationNode(p_eval, result_id); @@ -5982,10 +6006,14 @@ SpvReflectResult EvaluateResultImpl(SpvReflectPrvEvaluation* p_eval, uint32_t re case SpvOpSpecConstantTrue: case SpvOpSpecConstantFalse: case SpvOpSpecConstant: { - if (!p_node->spec_const) { + if (p_node->specId == INVALID_VALUE) { goto CONSTANT_RESULT; } - result->data.numeric.scalar = p_node->spec_const->current_value; + if (p_node->evaluation_state != SPV_REFLECT_EVALUATION_STATE_DONE && p_node->evaluation_state != SPV_REFLECT_EVALUATION_STATE_UPDATED) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + goto CLEANUP; + } + // no need to do anything... } break; case SpvOpSpecConstantComposite: @@ -6652,21 +6680,6 @@ SpvReflectResult EvaluateResultImpl(SpvReflectPrvEvaluation* p_eval, uint32_t re CHECK_IS_BOOLEAN_TYPE(operand1, res, CLEANUP) CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) - // cannot skip if type comes with result... - SpvReflectValue* operand2 = NULL; - GET_OPERAND((p_eval), (p_node), 5, operand2, res, CLEANUP) - if (operand2->type->id != result->type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - - SpvReflectValue* operand3 = NULL; - GET_OPERAND((p_eval), (p_node), 6, operand3, res, CLEANUP) - if (operand3->type->id != result->type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - uint32_t vec_size = 1; // result can be vector if operand is scalar. CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, operand1, result, res, CLEANUP); @@ -6676,17 +6689,35 @@ SpvReflectResult EvaluateResultImpl(SpvReflectPrvEvaluation* p_eval, uint32_t re res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; } + + SpvReflectValue* operand2 = NULL; + SpvReflectValue* operand3 = NULL; + for (uint32_t i = 0; i < vec_size; ++i) { if (operand1->data.numeric.vector.value[i].undefined_value) { result->data.numeric.vector.value[i].undefined_value = 1; } if (operand1->data.numeric.vector.value[i].value.uint32_bool_value) { + if(!operand2) { + GET_OPERAND((p_eval), (p_node), 5, operand2, res, CLEANUP) + if (operand2->type->id != result->type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + } if (operand2->data.numeric.vector.value[i].undefined_value) { result->data.numeric.vector.value[i].undefined_value = 1; } result->data.numeric.vector.value[i].value = operand2->data.numeric.vector.value[i].value; } else { + if(!operand3){ + GET_OPERAND((p_eval), (p_node), 6, operand3, res, CLEANUP) + if (operand3->type->id != result->type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + } if (operand3->data.numeric.vector.value[i].undefined_value) { result->data.numeric.vector.value[i].undefined_value = 1; } @@ -6704,14 +6735,26 @@ SpvReflectResult EvaluateResultImpl(SpvReflectPrvEvaluation* p_eval, uint32_t re } if (operand1->data.numeric.scalar.value.uint32_bool_value) { + SpvReflectValue* operand2 = NULL; + GET_OPERAND((p_eval), (p_node), 5, operand2, res, CLEANUP) + if (operand2->type->id != result->type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } // need deep copy if complex *result = *operand2; } else { + SpvReflectValue* operand3 = NULL; + GET_OPERAND((p_eval), (p_node), 6, operand3, res, CLEANUP) + if (operand3->type->id != result->type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } // need deep copy if complex *result = *operand3; } - if (operand1->data.numeric.vector.value[0].undefined_value) { + if (operand1->data.numeric.scalar.undefined_value) { // we shouldn't care about content here... for (uint32_t i = 0; i < SPV_REFLECT_MAX_VECTOR_DIMS; ++i) { result->data.numeric.vector.value[i].undefined_value = 1; @@ -6783,16 +6826,79 @@ SpvReflectResult EvaluateResultImpl(SpvReflectPrvEvaluation* p_eval, uint32_t re } -SpvReflectResult EvaluateResult(SpvReflectShaderModule* p_module, uint32_t result_id, const SpvReflectValue** result) +SpvReflectEvaluation* spvReflectGetEvaluationInterface(SpvReflectShaderModule* p_module) { - if (!result || !p_module) { - return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; + return p_module->_internal->evaluator; +} + +SpvReflectResult spvReflectSetSpecConstantValue(SpvReflectEvaluation* p_eval, uint32_t specId, SpvReflectScalarType type, const SpvReflectScalarValueData* value) +{ + SpvReflectPrvEvaluationNode* p_node = FindSpecIdNode(p_eval, specId); + if (!p_node) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; + } + switch (type) { + default: + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case SPIRV_REFLECT_SCALAR_TYPE_BOOL: + if (p_node->value.type->type_flags != SPV_REFLECT_TYPE_FLAG_BOOL) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + break; + case SPIRV_REFLECT_SCALAR_TYPE_I32: + case SPIRV_REFLECT_SCALAR_TYPE_I64: + if (p_node->value.type->type_flags != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + break; + case SPIRV_REFLECT_SCALAR_TYPE_F32: + case SPIRV_REFLECT_SCALAR_TYPE_F64: + if (p_node->value.type->type_flags != SPV_REFLECT_TYPE_FLAG_FLOAT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + break; } - if((p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT)==0){ - return SPV_REFLECT_RESULT_ERROR_PARSE_FAILED; + switch (type) { + default: + break; + case SPIRV_REFLECT_SCALAR_TYPE_I32: + case SPIRV_REFLECT_SCALAR_TYPE_F32: + if (p_node->value.type->traits.numeric.scalar.width != 32) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + break; + case SPIRV_REFLECT_SCALAR_TYPE_I64: + case SPIRV_REFLECT_SCALAR_TYPE_F64: + if (p_node->value.type->traits.numeric.scalar.width != 64) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + break; + } + p_node->value.data.numeric.scalar = *value; + p_node->evaluation_state = SPV_REFLECT_EVALUATION_STATE_UPDATED; + // update state tracking here... + // for now, all nodes are updated.... + + return SPV_REFLECT_RESULT_SUCCESS; +} + +SpvReflectResult spvReflectGetSpecConstantValue(SpvReflectEvaluation* p_eval, uint32_t specId, const SpvReflectValue** value) +{ + SpvReflectPrvEvaluationNode* p_node = FindSpecIdNode(p_eval, specId); + if (!p_node) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; + } + *value = &p_node->value; + return SPV_REFLECT_RESULT_SUCCESS; +} + +SpvReflectResult spvReflectEvaluateResult(SpvReflectEvaluation* p_eval, uint32_t result_id, const SpvReflectValue** result) +{ + if (!result || !p_eval) { + return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; } - // compute at most 100 instruction levels, maybe defining somewhere is better. - return EvaluateResultImpl(p_module->_internal->evaluator, result_id, result); + return EvaluateResultImpl(p_eval, result_id, result); } + diff --git a/spirv_reflect.h b/spirv_reflect.h index bc424515..1181ab90 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -405,8 +405,6 @@ typedef struct SpvReflectSpecializationConstant { const char* name; SpvReflectScalarValueData default_value; - SpvReflectScalarValueData current_value; - } SpvReflectSpecializationConstant; /*! @struct SpvReflectInterfaceVariable @@ -542,9 +540,10 @@ typedef struct SpvReflectEntryPoint { uint32_t output_vertices; // valid for geometry, tesselation } SpvReflectEntryPoint; -typedef struct SpvReflectPrvParser SpvReflectPrvParser; - -typedef struct SpvReflectPrvEvaluation SpvReflectPrvEvaluation; +/*! @struct SpvReflectEvaluation + @brief Opaque type that stores evaluation state and information +*/ +typedef struct SpvReflectEvaluation SpvReflectEvaluation; /*! @struct SpvReflectShaderModule @@ -585,7 +584,7 @@ typedef struct SpvReflectShaderModule { size_t type_description_count; SpvReflectTypeDescription* type_descriptions; - SpvReflectPrvEvaluation* evaluator; + SpvReflectEvaluation* evaluator; } * _internal; } SpvReflectShaderModule; @@ -1541,7 +1540,65 @@ const char* spvReflectBlockVariableTypeName( const SpvReflectBlockVariable* p_var ); -SpvReflectResult EvaluateResult(SpvReflectShaderModule* p_module, uint32_t result_id, const SpvReflectValue** result); + +/*! @fn spvReflectGetEvaluationInterface + @brief Retrieves the handle for evaluation + @param p_module Pointer to an instance of SpvReflectShaderModule. + @return If successful, returns the evaluation instance. + Otherwise, returns NULL. +*/ +SpvReflectEvaluation* spvReflectGetEvaluationInterface(SpvReflectShaderModule* p_module); + +typedef enum SpvReflectScalarType { + SPIRV_REFLECT_SCALAR_TYPE_INVALID, + SPIRV_REFLECT_SCALAR_TYPE_BOOL, + SPIRV_REFLECT_SCALAR_TYPE_I32, + SPIRV_REFLECT_SCALAR_TYPE_I64, + SPIRV_REFLECT_SCALAR_TYPE_F32, + SPIRV_REFLECT_SCALAR_TYPE_F64 +} SpvReflectScalarType; + +/*! @fn spvReflectSetSpecConstantValue + @brief Sets the current value of specialization constant. Type must follow c/c++ type aliasing rules. + @param p_eval Pointer to an instance of SpvReflectEvaluation. + @param specId Specialization constant id of the constant. + @param type Type of user specified value. For error checking. + @param value User provided value. + @return If successful, returns SPV_REFLECT_RESULT_SUCCESS. + Otherwise, the error code indicates the cause of + the failure. +*/ +SpvReflectResult spvReflectSetSpecConstantValue(SpvReflectEvaluation* p_eval, uint32_t specId, SpvReflectScalarType type, const SpvReflectScalarValueData* value); + +/*! @fn spvReflectGetSpecConstantValue + @brief Get the current value of specialization constant. Type must follow c/c++ type aliasing rules. + @param p_eval Pointer to an instance of SpvReflectEvaluation. + @param specId Specialization constant id of the constant. + @param value Current value. + @return If successful, returns SPV_REFLECT_RESULT_SUCCESS. + Otherwise, the error code indicates the cause of + the failure. +*/ +SpvReflectResult spvReflectGetSpecConstantValue(SpvReflectEvaluation* p_eval, uint32_t specId, const SpvReflectValue** value); + +/*! @fn spvReflectEvaluateResult + @brief Evaluates the result specified by result_id, only works for + constant expressions. + @param p_eval Pointer to an instance of SpvReflectEvaluation. + @param result_id The result id to retrieve + @param result pointer to hold result application can read from. + @return If successful, returns SPV_REFLECT_RESULT_SUCCESS. + Otherwise, the error code indicates the cause of + the failure. +*/ +SpvReflectResult spvReflectEvaluateResult(SpvReflectEvaluation* p_eval, uint32_t result_id, const SpvReflectValue** result); + + +SpvReflectResult spvReflectGetRelatedSpecIds(SpvReflectEvaluation* p_eval, uint32_t result_id, uint32_t* count, uint32_t* ids); + +/* + +*/ #if defined(__cplusplus) }; @@ -1651,7 +1708,12 @@ class ShaderModule { SpvReflectResult EvaluateResult(uint32_t result_id, const SpvReflectValue** result) { - return ::EvaluateResult(&m_module, result_id, result); + if (p_eval) { + return spvReflectEvaluateResult(p_eval, result_id, result); + } + else { + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + } } private: @@ -1662,6 +1724,7 @@ class ShaderModule { private: mutable SpvReflectResult m_result = SPV_REFLECT_RESULT_NOT_READY; SpvReflectShaderModule m_module = {}; + SpvReflectEvaluation* p_eval = nullptr; }; @@ -1687,6 +1750,7 @@ inline ShaderModule::ShaderModule(size_t size, const void* p_code, SpvReflectMod size, p_code, &m_module); + p_eval = spvReflectGetEvaluationInterface(&m_module); } /*! @fn ShaderModule @@ -1700,6 +1764,7 @@ inline ShaderModule::ShaderModule(const std::vector& code, SpvReflectMo code.size(), code.data(), &m_module); + p_eval = spvReflectGetEvaluationInterface(&m_module); } /*! @fn ShaderModule @@ -1713,6 +1778,7 @@ inline ShaderModule::ShaderModule(const std::vector& code, SpvReflectM code.size() * sizeof(uint32_t), code.data(), &m_module); + p_eval = spvReflectGetEvaluationInterface(&m_module); } /*! @fn ~ShaderModule From c000fdd089fb3457878e23203fa708705626311c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Tue, 2 Aug 2022 22:23:06 +0800 Subject: [PATCH 14/44] Naive implemenation Spec constant id are tracked by a id array. Better way would be evaluate the node early on, and put node pointers in nodes (actual tree). --- README.md | 5 +- spirv_reflect.c | 287 ++++++++++++++++++++++++++++++++++-------------- spirv_reflect.h | 16 ++- 3 files changed, 224 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index b044db9a..4042159f 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ SPIRV-Reflect has been tested on Linux and Windows. - Remap descriptor bindings at runtime, and update the source SPIR-V bytecode accordingly. - Log all reflection data as human-readable text. +- Experimental specialization constant parsing and evaluation ## Integration @@ -103,8 +104,8 @@ We tested the following bazel build command using Linux Bazel 1.2.1. bazel build :all ``` -## License - +## License + Copyright 2017-2018 Google Inc. Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/spirv_reflect.c b/spirv_reflect.c index a7092b01..c522c0c1 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -238,10 +238,21 @@ typedef struct SpvReflectPrvEvaluationNode { SpvReflectValue value; uint32_t specId; + + uint32_t related_id_count; + uint32_t* related_specId; } SpvReflectPrvEvaluationNode; // clang-format on // clang-format off +enum SpvReflectEvaluationFlagBits { + SPIRV_REFLECT_EVALUATION_FLAG_NONE = 0, + // traverse all branches, currently for OpSelect + SPIRV_REFLECT_EVALUATION_FLAG_ALL_BRANCH = 1 +}; + +typedef uint32_t SpvReflectEvaluationFlag; + typedef struct SpvReflectEvaluation { // original code if no-copy, else it's a copy of constant instructions size_t spirv_word_count; @@ -251,8 +262,9 @@ typedef struct SpvReflectEvaluation { SpvReflectPrvEvaluationNode* nodes; // To flag dry run and tree traversal... - uint32_t flags; - + SpvReflectEvaluationFlag flags; + // holds the buffer that stores spec id relations + uint32_t* specId_relation_buffer; // ohh I hope I could decouple this... But FindType uses this... // just a reference SpvReflectShaderModule* member_type_finder; @@ -1015,7 +1027,9 @@ static SpvReflectResult ParseStrings(SpvReflectPrvParser* p_parser) if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) { // Allocate string storage p_parser->strings = (SpvReflectPrvString*)calloc(p_parser->string_count, sizeof(*(p_parser->strings))); - + if(IsNull(p_parser->strings)){ + return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; + } uint32_t string_index = 0; for (size_t i = 0; i < p_parser->node_count; ++i) { SpvReflectPrvNode* p_node = &(p_parser->nodes[i]); @@ -1284,6 +1298,9 @@ static SpvReflectResult ParseFunctions(SpvReflectPrvParser* p_parser) } p_func->callee_ptrs = (SpvReflectPrvFunction**)calloc(p_func->callee_count, sizeof(*(p_func->callee_ptrs))); + if(IsNull(p_func->callee_ptrs)){ + return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; + } for (size_t j = 0, k = 0; j < p_func->callee_count; ++j) { while (p_parser->functions[k].id != p_func->callees[j]) { ++k; @@ -3546,9 +3563,12 @@ static SpvReflectResult ParserGetScalarConstant(const SpvReflectShaderModule* p_ #define MODULE_EVALUATION_FLAGS (SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT | SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT_NO_COPY) -#define IS_CONSTANT_LITERAL_OP(op_code)\ - (((op_code) == SpvOpSpecConstantTrue) || ((op_code) == SpvOpSpecConstantFalse) || ((op_code) == SpvOpSpecConstant) \ - || ((op_code) == SpvOpConstantTrue) || ((op_code) == SpvOpConstantFalse) || ((op_code) == SpvOpConstant)) +#define IS_SPEC_LITERAL_OP(op_code)\ + (((op_code) == SpvOpSpecConstantTrue) || ((op_code) == SpvOpSpecConstantFalse) || ((op_code) == SpvOpSpecConstant)) +#define IS_LITERAL_OP(op_code)\ + (((op_code) == SpvOpConstantTrue) || ((op_code) == SpvOpConstantFalse) || ((op_code) == SpvOpConstant)) +#define IS_CONSTANT_LITERAL_OP(op_code) (IS_SPEC_LITERAL_OP(op_code)||IS_LITERAL_OP(op_code)) +// constant null and constant sampler etc are not handled in literals or anywhere for now... #define IS_CONSTANT_OP(op_code) \ (IS_CONSTANT_LITERAL_OP(op_code) || ((op_code) == SpvOpSpecConstantOp) || ((op_code) == SpvOpSpecConstantComposite) \ || ((op_code) == SpvOpConstantComposite) || ((op_code) == SpvOpConstantNull) || ((op_code) == SpvOpConstantSampler) \ @@ -3581,6 +3601,9 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars } p_module->specialization_constants = (SpvReflectSpecializationConstant*)calloc(p_module->specialization_constant_count, sizeof(SpvReflectSpecializationConstant)); + if(IsNull(p_module->specialization_constants)){ + return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; + } uint32_t index = 0; @@ -3633,19 +3656,29 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars // need to evaluate expr later on... if (p_module->_internal->module_flags & MODULE_EVALUATION_FLAGS) { p_module->_internal->evaluator = (SpvReflectEvaluation*)calloc(1, sizeof(SpvReflectEvaluation)); + if(!p_module->_internal->evaluator){ + return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; + } + SpvReflectEvaluation* p_eval = p_module->_internal->evaluator; // needed for FindType for constituent types - p_module->_internal->evaluator->member_type_finder = p_module; - p_module->_internal->evaluator->node_count = constant_instruction_num; - p_module->_internal->evaluator->nodes = (SpvReflectPrvEvaluationNode*)calloc(constant_instruction_num,sizeof(SpvReflectPrvEvaluationNode)); + p_eval->member_type_finder = p_module; + p_eval->node_count = constant_instruction_num; + p_eval->nodes = (SpvReflectPrvEvaluationNode*)calloc(constant_instruction_num,sizeof(SpvReflectPrvEvaluationNode)); + if(!p_eval->nodes){ + return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; + } if (p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT_NO_COPY) { // use original code for evaluation. - p_module->_internal->evaluator->spirv_code = p_module->_internal->spirv_code; - p_module->_internal->evaluator->spirv_word_count = p_module->_internal->spirv_word_count; + p_eval->spirv_code = p_module->_internal->spirv_code; + p_eval->spirv_word_count = p_module->_internal->spirv_word_count; } else if (p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT) { // need to copy instructions from code for later evaluation. - p_module->_internal->evaluator->spirv_code = (uint32_t*)malloc(instruction_size * sizeof(uint32_t)); - p_module->_internal->evaluator->spirv_word_count = instruction_size; + p_eval->spirv_code = (uint32_t*)malloc(instruction_size * sizeof(uint32_t)); + if (!p_module->_internal->evaluator->spirv_code) { + return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; + } + p_eval->spirv_word_count = instruction_size; } // need to update correct offset in new code if not no-copy @@ -3655,37 +3688,109 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars SpvReflectPrvNode* p_node = &(p_parser->nodes[i]); // constant types need to be tracked after parser is dead... if (IS_CONSTANT_OP(p_node->op)) { - p_module->_internal->evaluator->nodes[current_cinst].op = p_node->op; - p_module->_internal->evaluator->nodes[current_cinst].result_id = p_node->result_id; - p_module->_internal->evaluator->nodes[current_cinst].word_count = p_node->word_count; - p_module->_internal->evaluator->nodes[current_cinst].value.type = FindType(p_module, p_node->result_type_id); + p_eval->nodes[current_cinst].op = p_node->op; + p_eval->nodes[current_cinst].result_id = p_node->result_id; + p_eval->nodes[current_cinst].word_count = p_node->word_count; + p_eval->nodes[current_cinst].value.type = FindType(p_module, p_node->result_type_id); if (!p_module->_internal->evaluator->nodes[current_cinst].value.type) { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; } - p_module->_internal->evaluator->nodes[current_cinst].evaluation_state = SPV_REFLECT_EVALUATION_STATE_UNINITIALIZED; + p_eval->nodes[current_cinst].evaluation_state = SPV_REFLECT_EVALUATION_STATE_UNINITIALIZED; if (IS_CONSTANT_LITERAL_OP(p_node->op)) { SpvReflectResult res = ParserGetScalarConstant(p_module, p_parser, p_node, - &p_module->_internal->evaluator->nodes[current_cinst].value.data.numeric.scalar, - &p_module->_internal->evaluator->nodes[current_cinst].value.type); + &p_eval->nodes[current_cinst].value.data.numeric.scalar, + &p_eval->nodes[current_cinst].value.type); if (res == SPV_REFLECT_RESULT_SUCCESS) { - p_module->_internal->evaluator->nodes[current_cinst].evaluation_state = SPV_REFLECT_EVALUATION_STATE_DONE; + p_eval->nodes[current_cinst].evaluation_state = SPV_REFLECT_EVALUATION_STATE_DONE; } else { - p_module->_internal->evaluator->nodes[current_cinst].evaluation_state = SPV_REFLECT_EVALUATION_STATE_FAILED; + p_eval->nodes[current_cinst].evaluation_state = SPV_REFLECT_EVALUATION_STATE_FAILED; } } - p_module->_internal->evaluator->nodes[current_cinst].specId = p_node->decorations.specialization_constant.value; + p_eval->nodes[current_cinst].specId = p_node->decorations.specialization_constant.value; if (p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT_NO_COPY) { - p_module->_internal->evaluator->nodes[current_cinst].word_offset = p_node->word_offset; + p_eval->nodes[current_cinst].word_offset = p_node->word_offset; } else { - p_module->_internal->evaluator->nodes[current_cinst].word_offset = current_offset; + p_eval->nodes[current_cinst].word_offset = current_offset; memcpy(p_module->_internal->evaluator->spirv_code + current_offset, p_module->_internal->spirv_code + p_node->word_offset, 4 * p_node->word_count); } ++current_cinst; current_offset += p_node->word_count; } } + + // now evaluation is initialized, find out relations here. + // a better way is to write the evaluation tree again, and build an actual tree, + // but that would be really difficult... + uint32_t orig_flag = p_eval->flags; + p_eval->flags |= SPIRV_REFLECT_EVALUATION_FLAG_ALL_BRANCH; + uint32_t total_specId_relation = 0; + for (uint32_t i = 0; i < p_eval->node_count; ++i) { + SpvReflectPrvEvaluationNode* p_ev_node = &p_eval->nodes[i]; + // do not need to find what constant literals are related to + if(!IS_CONSTANT_LITERAL_OP(p_ev_node->op)){ + // reset evaluation state for tracking which ones are touched + for (uint32_t j = 0; j < p_eval->node_count; ++j) { + p_eval->nodes[j].evaluation_state = SPV_REFLECT_EVALUATION_STATE_UPDATED; + } + // we don't care about result here. + const SpvReflectValue* evaluated; + SpvReflectResult res = spvReflectEvaluateResult(p_eval, p_ev_node->result_id, &evaluated); + // will always succeed if types match and evaluation supports the whole tree + // just the ops we need. + if (res == SPV_REFLECT_RESULT_SUCCESS) { + // count how many specId are touched. + for (uint32_t j = 0; j < p_eval->node_count; ++j) { + if(p_eval->nodes[j].specId!=INVALID_VALUE && p_eval->nodes[j].evaluation_state!= SPV_REFLECT_EVALUATION_STATE_UPDATED) { + ++total_specId_relation; + } + } + } + } + } + + if(total_specId_relation){ + p_eval->specId_relation_buffer = (uint32_t*)malloc(total_specId_relation * 4); + if(!p_eval->specId_relation_buffer){ + return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; + } + // now fill the relation buffer. Same path. + uint32_t offset = 0; + for (uint32_t i = 0; i < p_eval->node_count; ++i) { + SpvReflectPrvEvaluationNode* p_ev_node = &p_eval->nodes[i]; + // do not need to find what constant literals are related to + if (!IS_CONSTANT_LITERAL_OP(p_ev_node->op)) { + // reset evaluation state for tracking which ones are touched + for (uint32_t j = 0; j < p_eval->node_count; ++j) { + p_eval->nodes[j].evaluation_state = SPV_REFLECT_EVALUATION_STATE_UPDATED; + } + // we don't care about result here. + const SpvReflectValue* evaluated; + SpvReflectResult res = spvReflectEvaluateResult(p_eval, p_ev_node->result_id, &evaluated); + // will always succeed if types match and evaluation supports the whole tree + // just the ops we need. + if (res == SPV_REFLECT_RESULT_SUCCESS) { + // count how many specId are touched. + uint32_t node_spec_id_count = 0; + p_ev_node->related_specId = p_eval->specId_relation_buffer + offset; + for (uint32_t j = 0; j < p_eval->node_count; ++j) { + if (p_eval->nodes[j].specId != INVALID_VALUE && p_eval->nodes[j].evaluation_state != SPV_REFLECT_EVALUATION_STATE_UPDATED) { + p_eval->specId_relation_buffer[offset] = p_eval->nodes[j].specId; + ++node_spec_id_count; + ++offset; + } + } + if (!node_spec_id_count) { + p_ev_node->related_specId = NULL; + } + p_ev_node->related_id_count = node_spec_id_count; + } + } + } + } + + p_eval->flags = orig_flag; } return SPV_REFLECT_RESULT_SUCCESS; @@ -3905,7 +4010,9 @@ static SpvReflectResult ParseDescriptorSets(SpvReflectShaderModule* p_module) for (uint32_t i = 0; i descriptor_set_count; ++i) { SpvReflectDescriptorSet* p_set = &(p_module->descriptor_sets[i]); p_set->bindings = (SpvReflectDescriptorBinding **)calloc(p_set->binding_count, sizeof(*(p_set->bindings))); - + if (IsNull(p_set->bindings)) { + return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; + } uint32_t descriptor_index = 0; for (uint32_t j = 0; j < p_module->descriptor_binding_count; ++j) { SpvReflectDescriptorBinding* p_descriptor = &(p_module->descriptor_bindings[j]); @@ -4010,12 +4117,9 @@ static SpvReflectResult CreateShaderModule( // parser now works in internal field of p_module. SpvReflectPrvParser parser = { 0 }; - // SpvReflectPrvParser* parser = (SpvReflectPrvParser*)calloc(1,sizeof(SpvReflectPrvParser)); SpvReflectResult result = CreateParser(p_module->_internal->spirv_size, p_module->_internal->spirv_code, &parser); - // used by spec constant parsing GetScalarConstant - //p_module->_internal->parser = parser; // Generator { @@ -5474,8 +5578,8 @@ SpvReflectSpecializationConstant* GetSpecContantById(const SpvReflectShaderModul SpvReflectResult GetMemberByIndex(const SpvReflectShaderModule* p_module, const SpvReflectValueData* mother, const SpvReflectTypeDescription* mother_type, uint32_t index, SpvReflectValueData** result, const SpvReflectTypeDescription** child_type) { - if (!mother_type || !(mother_type->type_flags & VECTOR_DISALLOWED_FLAGS)) { - if (!mother_type || !(mother_type->type_flags & SCALAR_DISALLOWED_FLAGS)) { + if (!(mother_type->type_flags & VECTOR_DISALLOWED_FLAGS)) { + if (!(mother_type->type_flags & SCALAR_DISALLOWED_FLAGS)) { // scalar types have no composition return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } @@ -5500,8 +5604,8 @@ SpvReflectResult GetMemberByIndex(const SpvReflectShaderModule* p_module, const SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflectValueData* dst, SpvReflectValueData* src) { - if (!type || !(type->type_flags & VECTOR_DISALLOWED_FLAGS)) { - if (!type || !(type->type_flags & SCALAR_DISALLOWED_FLAGS)) { + if (!(type->type_flags & VECTOR_DISALLOWED_FLAGS)) { + if (!(type->type_flags & SCALAR_DISALLOWED_FLAGS)) { dst->numeric.scalar = src->numeric.scalar; // scalar types have no composition return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; @@ -5525,7 +5629,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect #define CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_result, p_op1, res, CLEANUP) \ { \ - if ((p_result)->type && (p_result)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + if ((p_result)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ if (!((p_op1)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ goto CLEANUP; \ @@ -5540,12 +5644,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect #define CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, p_result, p_op1, p_op2, res, CLEANUP)\ { \ - /* may be scalar boolean if type == null, but never p_result */ \ - if ((p_result)->type && (p_result)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ - if(!(p_op1)->type || !(p_op2)->type) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ + if ((p_result)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ if (!((p_op1)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ goto CLEANUP; \ @@ -5574,7 +5673,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect } \ } -#define CHECK_IS_BASIC_TYPE(p_result, b_type, res, CLEANUP) \ +#define CHECK_IS_BASIC_TYPE(p_result, b_type, res, CLEANUP) \ { \ if(((p_result)->type->type_flags & SCALAR_TYPE_FLAGS) != b_type) { \ res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ @@ -5595,12 +5694,13 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect } \ } \ -#define GET_OPERAND(eval, p_node, offset, p_operand, res, CLEANUP) \ -{ \ - uint32_t operand_id; \ - EVAL_CHECKED_READU32(eval, p_node->word_offset + offset, operand_id, res, CLEANUP); \ - res = EvaluateResultImpl(eval, operand_id, &(p_operand)); \ - if (res != SPV_REFLECT_RESULT_SUCCESS) goto CLEANUP; \ +#define GET_OPERAND(eval, p_node, offset, p_operand, res, CLEANUP) \ +{ \ + uint32_t operand_id; \ + EVAL_CHECKED_READU32(eval, p_node->word_offset + offset, operand_id, res, CLEANUP); \ + res = EvaluateResultImpl(eval, operand_id, &(p_operand)); \ + /* ignore_eval_error is used for traversing tree without calculating. */ \ + if (res != SPV_REFLECT_RESULT_SUCCESS) goto CLEANUP; \ } #define SIMPLE_UNARY_OP_32_BIT_HOOK @@ -5983,6 +6083,7 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul if (p_node->evaluation_state == SPV_REFLECT_EVALUATION_STATE_DONE) { return SPV_REFLECT_RESULT_SUCCESS; } + uint32_t orig_state = p_node->evaluation_state; p_node->evaluation_state = SPV_REFLECT_EVALUATION_STATE_WORKING; switch (p_node->op) { @@ -6009,7 +6110,7 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul if (p_node->specId == INVALID_VALUE) { goto CONSTANT_RESULT; } - if (p_node->evaluation_state != SPV_REFLECT_EVALUATION_STATE_DONE && p_node->evaluation_state != SPV_REFLECT_EVALUATION_STATE_UPDATED) { + if (orig_state != SPV_REFLECT_EVALUATION_STATE_DONE && orig_state != SPV_REFLECT_EVALUATION_STATE_UPDATED) { res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; goto CLEANUP; } @@ -6598,24 +6699,11 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul } } - if (!current_type) { - if (operand1->type && (operand1->type->type_flags != SPV_REFLECT_TYPE_FLAG_BOOL)) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - } - else { - if (operand1->type) { - if (current_type->id != operand1->type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - } - else if (current_type->type_flags != SPV_REFLECT_TYPE_FLAG_BOOL) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } + if (current_type->id != operand1->type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } + res = CopyValueData(current_type, current_data, &operand1->data); if (res != SPV_REFLECT_RESULT_SUCCESS) { goto CLEANUP; @@ -6684,15 +6772,30 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul // result can be vector if operand is scalar. CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, operand1, result, res, CLEANUP); + + SpvReflectValue* operand2 = NULL; + if (p_eval->flags & SPIRV_REFLECT_EVALUATION_FLAG_ALL_BRANCH) { + GET_OPERAND((p_eval), (p_node), 5, operand2, res, CLEANUP) + if (operand2->type->id != result->type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + } + SpvReflectValue* operand3 = NULL; + if (p_eval->flags & SPIRV_REFLECT_EVALUATION_FLAG_ALL_BRANCH) { + GET_OPERAND((p_eval), (p_node), 6, operand3, res, CLEANUP) + if (operand3->type->id != result->type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + } + if (vec_size != 1) { if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; } - SpvReflectValue* operand2 = NULL; - SpvReflectValue* operand3 = NULL; - for (uint32_t i = 0; i < vec_size; ++i) { if (operand1->data.numeric.vector.value[i].undefined_value) { result->data.numeric.vector.value[i].undefined_value = 1; @@ -6735,21 +6838,23 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul } if (operand1->data.numeric.scalar.value.uint32_bool_value) { - SpvReflectValue* operand2 = NULL; - GET_OPERAND((p_eval), (p_node), 5, operand2, res, CLEANUP) - if (operand2->type->id != result->type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; + if(!operand2) { + GET_OPERAND((p_eval), (p_node), 5, operand2, res, CLEANUP) + if (operand2->type->id != result->type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } } // need deep copy if complex *result = *operand2; } else { - SpvReflectValue* operand3 = NULL; - GET_OPERAND((p_eval), (p_node), 6, operand3, res, CLEANUP) - if (operand3->type->id != result->type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; + if(!operand3) { + GET_OPERAND((p_eval), (p_node), 6, operand3, res, CLEANUP) + if (operand3->type->id != result->type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } } // need deep copy if complex *result = *operand3; @@ -6877,8 +6982,18 @@ SpvReflectResult spvReflectSetSpecConstantValue(SpvReflectEvaluation* p_eval, ui p_node->value.data.numeric.scalar = *value; p_node->evaluation_state = SPV_REFLECT_EVALUATION_STATE_UPDATED; // update state tracking here... - // for now, all nodes are updated.... - + for (uint32_t i = 0; i < p_eval->node_count; ++i) { + bool exist_in_op = false; + for (uint32_t j = 0; j < p_eval->nodes[i].related_id_count; ++j) { + if (p_eval->nodes[i].related_specId[j] == specId) { + exist_in_op = true; + break; + } + } + if (exist_in_op) { + p_eval->nodes[i].evaluation_state = SPV_REFLECT_EVALUATION_STATE_UPDATED; + } + } return SPV_REFLECT_RESULT_SUCCESS; } @@ -6900,5 +7015,17 @@ SpvReflectResult spvReflectEvaluateResult(SpvReflectEvaluation* p_eval, uint32_t return EvaluateResultImpl(p_eval, result_id, result); } +int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id, uint32_t specId) +{ + SpvReflectPrvEvaluationNode* p_node = FindEvaluationNode(p_eval, result_id); + if (!p_node) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; + } + for (uint32_t i = 0; i < p_node->related_id_count; ++i) { + if (p_node->related_specId[i] == specId) return 1; + } + return 0; +} + diff --git a/spirv_reflect.h b/spirv_reflect.h index 1181ab90..96320ba7 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -1593,8 +1593,20 @@ SpvReflectResult spvReflectGetSpecConstantValue(SpvReflectEvaluation* p_eval, ui */ SpvReflectResult spvReflectEvaluateResult(SpvReflectEvaluation* p_eval, uint32_t result_id, const SpvReflectValue** result); - -SpvReflectResult spvReflectGetRelatedSpecIds(SpvReflectEvaluation* p_eval, uint32_t result_id, uint32_t* count, uint32_t* ids); +/*! @fn spvReflectEvaluateResult + @brief Get the specialization constant ids that MAY have an impact on + given result if changed. Composting, de-compositing, + (b.x = a, c = b.x), select with non-specialized true/false (1?b:c) + are NOT tracked and cleaned up. This may be extened to track the + whole tree, but is not the concern of this library. + If the resultid's tree cannot be correctly evaluated, count would be 0. + @param p_eval Pointer to an instance of SpvReflectEvaluation. + @param result_id The result id in concern + @param specId The specId in concern + @param ids Readonly array of specids + @return 1 if may be related, 0 otherwise +*/ +int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id, uint32_t specId); /* From a52e29e3ae64fd57f2816182039842b118a4711d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Fri, 5 Aug 2022 23:26:19 +0800 Subject: [PATCH 15/44] Refactor code Now the ast is an actual ast. Now spirv code can be safely deleted. --- spirv_reflect.c | 2413 ++++++++++++++++++++++++++++------------------- spirv_reflect.h | 2 +- 2 files changed, 1432 insertions(+), 983 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index c522c0c1..44263242 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -217,41 +217,46 @@ typedef struct SpvReflectPrvParser { } SpvReflectPrvParser; // clang-format on -typedef enum SpvReflectEvaluationState { - SPV_REFLECT_EVALUATION_STATE_UNINITIALIZED = 0, +typedef enum SpvReflectEvaluationNodeState { + SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED = 0, + SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED = 1, + SPV_REFLECT_EVALUATION_NODE_STATE_PENDING = 2, // for tracking recursion - SPV_REFLECT_EVALUATION_STATE_WORKING = 1, - SPV_REFLECT_EVALUATION_STATE_DONE = 2, + SPV_REFLECT_EVALUATION_NODE_STATE_WORKING = 3, + SPV_REFLECT_EVALUATION_NODE_STATE_DONE = 4, // for possible update tracking - SPV_REFLECT_EVALUATION_STATE_UPDATED = 3, + SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED = 5, // failed evaluation - SPV_REFLECT_EVALUATION_STATE_FAILED = 4 -}SpvReflectEvaluationState; + SPV_REFLECT_EVALUATION_NODE_STATE_FAILED = 6 +}SpvReflectEvaluationNodeState; // clang-format off +typedef struct SpvReflectPrvEvaluationNode SpvReflectPrvEvaluationNode; typedef struct SpvReflectPrvEvaluationNode { uint32_t result_id; SpvOp op; + SpvOp specOp; uint32_t word_offset; uint32_t word_count; - SpvReflectEvaluationState evaluation_state; + SpvReflectEvaluationNodeState evaluation_state; SpvReflectValue value; uint32_t specId; - uint32_t related_id_count; - uint32_t* related_specId; + uint32_t num_id_operands; + SpvReflectPrvEvaluationNode** id_operands; + uint32_t num_literal_words; + uint32_t* literal_words; } SpvReflectPrvEvaluationNode; // clang-format on // clang-format off -enum SpvReflectEvaluationFlagBits { - SPIRV_REFLECT_EVALUATION_FLAG_NONE = 0, +typedef enum SpvReflectEvaluationState { + SPIRV_REFLECT_EVALUATION_MODE_NORMAL = 0, // traverse all branches, currently for OpSelect - SPIRV_REFLECT_EVALUATION_FLAG_ALL_BRANCH = 1 -}; - -typedef uint32_t SpvReflectEvaluationFlag; + SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS = 1, + SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS = 2, +} SpvReflectEvaluationState; typedef struct SpvReflectEvaluation { // original code if no-copy, else it's a copy of constant instructions @@ -262,9 +267,11 @@ typedef struct SpvReflectEvaluation { SpvReflectPrvEvaluationNode* nodes; // To flag dry run and tree traversal... - SpvReflectEvaluationFlag flags; - // holds the buffer that stores spec id relations - uint32_t* specId_relation_buffer; + SpvReflectEvaluationState state; + + SpvReflectPrvEvaluationNode** id_operand_buffer; + uint32_t* literal_word_buffer; + // ohh I hope I could decouple this... But FindType uses this... // just a reference SpvReflectShaderModule* member_type_finder; @@ -3577,6 +3584,10 @@ static SpvReflectResult ParserGetScalarConstant(const SpvReflectShaderModule* p_ // defined later.. static SpvReflectSpecializationConstant* GetSpecContantById(const SpvReflectShaderModule* p_module, uint32_t constant_id); +static SpvReflectResult EvaluateResult_Do(SpvReflectPrvEvaluationNode* p_node); +static SpvReflectResult EvaluateResult_1PASS(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node); +static SpvReflectResult EvaluateResult_2PASS(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node); + static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) { p_module->specialization_constant_count = 0; @@ -3689,22 +3700,23 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars // constant types need to be tracked after parser is dead... if (IS_CONSTANT_OP(p_node->op)) { p_eval->nodes[current_cinst].op = p_node->op; + p_eval->nodes[current_cinst].specOp = (SpvOp)INVALID_VALUE; p_eval->nodes[current_cinst].result_id = p_node->result_id; p_eval->nodes[current_cinst].word_count = p_node->word_count; p_eval->nodes[current_cinst].value.type = FindType(p_module, p_node->result_type_id); if (!p_module->_internal->evaluator->nodes[current_cinst].value.type) { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; } - p_eval->nodes[current_cinst].evaluation_state = SPV_REFLECT_EVALUATION_STATE_UNINITIALIZED; + p_eval->nodes[current_cinst].evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED; if (IS_CONSTANT_LITERAL_OP(p_node->op)) { SpvReflectResult res = ParserGetScalarConstant(p_module, p_parser, p_node, &p_eval->nodes[current_cinst].value.data.numeric.scalar, &p_eval->nodes[current_cinst].value.type); if (res == SPV_REFLECT_RESULT_SUCCESS) { - p_eval->nodes[current_cinst].evaluation_state = SPV_REFLECT_EVALUATION_STATE_DONE; + p_eval->nodes[current_cinst].evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_DONE; } else { - p_eval->nodes[current_cinst].evaluation_state = SPV_REFLECT_EVALUATION_STATE_FAILED; + p_eval->nodes[current_cinst].evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_FAILED; } } p_eval->nodes[current_cinst].specId = p_node->decorations.specialization_constant.value; @@ -3719,80 +3731,60 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars current_offset += p_node->word_count; } } - - // now evaluation is initialized, find out relations here. - // a better way is to write the evaluation tree again, and build an actual tree, - // but that would be really difficult... - uint32_t orig_flag = p_eval->flags; - p_eval->flags |= SPIRV_REFLECT_EVALUATION_FLAG_ALL_BRANCH; - uint32_t total_specId_relation = 0; + + // 1 PASS, get number of bytes to allocate... for (uint32_t i = 0; i < p_eval->node_count; ++i) { SpvReflectPrvEvaluationNode* p_ev_node = &p_eval->nodes[i]; // do not need to find what constant literals are related to if(!IS_CONSTANT_LITERAL_OP(p_ev_node->op)){ // reset evaluation state for tracking which ones are touched - for (uint32_t j = 0; j < p_eval->node_count; ++j) { - p_eval->nodes[j].evaluation_state = SPV_REFLECT_EVALUATION_STATE_UPDATED; - } - // we don't care about result here. - const SpvReflectValue* evaluated; - SpvReflectResult res = spvReflectEvaluateResult(p_eval, p_ev_node->result_id, &evaluated); - // will always succeed if types match and evaluation supports the whole tree - // just the ops we need. - if (res == SPV_REFLECT_RESULT_SUCCESS) { - // count how many specId are touched. - for (uint32_t j = 0; j < p_eval->node_count; ++j) { - if(p_eval->nodes[j].specId!=INVALID_VALUE && p_eval->nodes[j].evaluation_state!= SPV_REFLECT_EVALUATION_STATE_UPDATED) { - ++total_specId_relation; - } - } - } + EvaluateResult_1PASS(p_eval, p_ev_node); } } - - if(total_specId_relation){ - p_eval->specId_relation_buffer = (uint32_t*)malloc(total_specId_relation * 4); - if(!p_eval->specId_relation_buffer){ - return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; - } - // now fill the relation buffer. Same path. - uint32_t offset = 0; - for (uint32_t i = 0; i < p_eval->node_count; ++i) { + uint32_t literal_words = 0; + uint32_t id_operands = 0; + for (uint32_t i = 0; i < p_eval->node_count; ++i) { SpvReflectPrvEvaluationNode* p_ev_node = &p_eval->nodes[i]; // do not need to find what constant literals are related to - if (!IS_CONSTANT_LITERAL_OP(p_ev_node->op)) { - // reset evaluation state for tracking which ones are touched - for (uint32_t j = 0; j < p_eval->node_count; ++j) { - p_eval->nodes[j].evaluation_state = SPV_REFLECT_EVALUATION_STATE_UPDATED; - } - // we don't care about result here. - const SpvReflectValue* evaluated; - SpvReflectResult res = spvReflectEvaluateResult(p_eval, p_ev_node->result_id, &evaluated); - // will always succeed if types match and evaluation supports the whole tree - // just the ops we need. - if (res == SPV_REFLECT_RESULT_SUCCESS) { - // count how many specId are touched. - uint32_t node_spec_id_count = 0; - p_ev_node->related_specId = p_eval->specId_relation_buffer + offset; - for (uint32_t j = 0; j < p_eval->node_count; ++j) { - if (p_eval->nodes[j].specId != INVALID_VALUE && p_eval->nodes[j].evaluation_state != SPV_REFLECT_EVALUATION_STATE_UPDATED) { - p_eval->specId_relation_buffer[offset] = p_eval->nodes[j].specId; - ++node_spec_id_count; - ++offset; - } - } - if (!node_spec_id_count) { - p_ev_node->related_specId = NULL; - } - p_ev_node->related_id_count = node_spec_id_count; - } + if (!IS_CONSTANT_LITERAL_OP(p_ev_node->op) && p_ev_node->evaluation_state == SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED) { + // reset evaluation state for tracking which ones are touched + literal_words += p_ev_node->num_literal_words; + id_operands += p_ev_node->num_id_operands; } + } + + p_eval->id_operand_buffer = (SpvReflectPrvEvaluationNode**)malloc(id_operands *sizeof(SpvReflectPrvEvaluationNode*)); + if(IsNull(p_eval->id_operand_buffer)){ + return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; + } + p_eval->literal_word_buffer = (uint32_t*)malloc(literal_words * sizeof(uint32_t)); + if(IsNull(p_eval->literal_word_buffer)){ + return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; + } + uint32_t id_offset = 0; + uint32_t literal_offset = 0; + for (uint32_t i = 0; i < p_eval->node_count; ++i) { + SpvReflectPrvEvaluationNode* p_ev_node = &p_eval->nodes[i]; + // do not need to find what constant literals are related to + if (!IS_CONSTANT_LITERAL_OP(p_ev_node->op) && p_ev_node->evaluation_state == SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED) { + p_ev_node->id_operands = p_eval->id_operand_buffer + id_offset; + p_ev_node->literal_words = p_eval->literal_word_buffer + literal_offset; + literal_offset += p_ev_node->num_literal_words; + id_offset += p_ev_node->num_id_operands; + } + } + // 2 PASS + for (uint32_t i = 0; i < p_eval->node_count; ++i) { + SpvReflectPrvEvaluationNode* p_ev_node = &p_eval->nodes[i]; + // do not need to find what constant literals are related to + if(!IS_CONSTANT_LITERAL_OP(p_ev_node->op)){ + // reset evaluation state for tracking which ones are touched + EvaluateResult_2PASS(p_eval, p_ev_node); } } - - p_eval->flags = orig_flag; } + return SPV_REFLECT_RESULT_SUCCESS; } @@ -3802,6 +3794,8 @@ static void DestroyEvaluator(SpvReflectEvaluation* evaluator, bool owns_code) if (owns_code) { SafeFree(evaluator->spirv_code); } + SafeFree(evaluator->id_operand_buffer); + SafeFree(evaluator->literal_word_buffer); } @@ -5593,7 +5587,9 @@ SpvReflectResult GetMemberByIndex(const SpvReflectShaderModule* p_module, const return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; } *child_type = c_type; - *result = (SpvReflectValueData*)&mother->numeric.vector.value[index]; + if(mother){ + *result = (SpvReflectValueData*)&mother->numeric.vector.value[index]; + } return SPV_REFLECT_RESULT_SUCCESS; } } @@ -5627,261 +5623,327 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect } \ } -#define CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_result, p_op1, res, CLEANUP) \ +#define CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_result_node, p_op1_node, res, CLEANUP) \ { \ - if ((p_result)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ - if (!((p_op1)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ + if ((p_result_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + if (!((p_op1_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ goto CLEANUP; \ } \ - if ((p_op1)->type->traits.numeric.vector.component_count != (p_result)->type->traits.numeric.vector.component_count) { \ + if ((p_op1_node)->value.type->traits.numeric.vector.component_count != (p_result_node)->value.type->traits.numeric.vector.component_count) { \ res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ goto CLEANUP; \ } \ - vec_size = (p_result)->type->traits.numeric.vector.component_count; \ + vec_size = (p_result_node)->value.type->traits.numeric.vector.component_count; \ } \ } -#define CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, p_result, p_op1, p_op2, res, CLEANUP)\ +#define CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, p_result_node, p_op1_node, p_op2_node, res, CLEANUP)\ { \ - if ((p_result)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ - if (!((p_op1)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ + if ((p_result_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + if (!((p_op1_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ goto CLEANUP; \ } \ - if (!((p_op2)->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ + if (!((p_op2_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ goto CLEANUP; \ } \ - if ((p_op1)->type->traits.numeric.vector.component_count != (p_result)->type->traits.numeric.vector.component_count) { \ + if ((p_op1_node)->value.type->traits.numeric.vector.component_count != (p_result_node)->value.type->traits.numeric.vector.component_count) { \ res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ goto CLEANUP; \ } \ - if ((p_op2)->type->traits.numeric.vector.component_count != (p_result)->type->traits.numeric.vector.component_count) { \ + if ((p_op2_node)->value.type->traits.numeric.vector.component_count != (p_result_node)->value.type->traits.numeric.vector.component_count) { \ res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ goto CLEANUP; \ } \ - vec_size = (p_result)->type->traits.numeric.vector.component_count; \ + vec_size = (p_result_node)->value.type->traits.numeric.vector.component_count; \ } \ } -#define CHECK_WIDTH_MATCH(p_value1, p_value2, res, CLEANUP) \ +#define CHECK_WIDTH_MATCH(p_node1, p_node2, res, CLEANUP) \ { \ - if ((p_value2)->type->traits.numeric.scalar.width != (p_value1)->type->traits.numeric.scalar.width) { \ + if ((p_node1)->value.type->traits.numeric.scalar.width != (p_node2)->value.type->traits.numeric.scalar.width) { \ res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ goto CLEANUP; \ } \ } -#define CHECK_IS_BASIC_TYPE(p_result, b_type, res, CLEANUP) \ +#define CHECK_IS_BASIC_TYPE(p_result_node, b_type, res, CLEANUP) \ { \ - if(((p_result)->type->type_flags & SCALAR_TYPE_FLAGS) != b_type) { \ + if(((p_result_node)->value.type->type_flags & SCALAR_TYPE_FLAGS) != b_type) { \ res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ goto CLEANUP; \ } \ } -#define CHECK_IS_INTEGER_TYPE(p_result, res, CLEANUP) CHECK_IS_BASIC_TYPE(p_result, SPV_REFLECT_TYPE_FLAG_INT, res, CLEANUP) -#define CHECK_IS_FLOAT_TYPE(p_result, res, CLEANUP) CHECK_IS_BASIC_TYPE(p_result, SPV_REFLECT_TYPE_FLAG_FLOAT, res, CLEANUP) -#define CHECK_IS_BOOLEAN_TYPE(p_result, res, CLEANUP) CHECK_IS_BASIC_TYPE(p_result, SPV_REFLECT_TYPE_FLAG_BOOL, res, CLEANUP) +#define CHECK_IS_INTEGER_TYPE(p_result_node, res, CLEANUP) CHECK_IS_BASIC_TYPE(p_result_node, SPV_REFLECT_TYPE_FLAG_INT, res, CLEANUP) +#define CHECK_IS_FLOAT_TYPE(p_result_node, res, CLEANUP) CHECK_IS_BASIC_TYPE(p_result_node, SPV_REFLECT_TYPE_FLAG_FLOAT, res, CLEANUP) +#define CHECK_IS_BOOLEAN_TYPE(p_result_node, res, CLEANUP) CHECK_IS_BASIC_TYPE(p_result_node, SPV_REFLECT_TYPE_FLAG_BOOL, res, CLEANUP) -#define CHECK_VECTOR_OR_SCALAR_TYPE(p_result, res, CLEANUP) \ +#define CHECK_VECTOR_OR_SCALAR_TYPE(p_result_node, res, CLEANUP) \ { \ - if ((p_result)->type && ((p_result)->type->type_flags & VECTOR_DISALLOWED_FLAGS)) { \ + if ((p_result_node)->value.type && ((p_result_node)->value.type->type_flags & VECTOR_DISALLOWED_FLAGS)) { \ res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ goto CLEANUP; \ } \ } \ -#define GET_OPERAND(eval, p_node, offset, p_operand, res, CLEANUP) \ +#define GET_OPERAND(eval, p_node, offset, p_result_node, res, CLEANUP) \ { \ uint32_t operand_id; \ EVAL_CHECKED_READU32(eval, p_node->word_offset + offset, operand_id, res, CLEANUP); \ - res = EvaluateResultImpl(eval, operand_id, &(p_operand)); \ - /* ignore_eval_error is used for traversing tree without calculating. */ \ - if (res != SPV_REFLECT_RESULT_SUCCESS) goto CLEANUP; \ + p_result_node = FindEvaluationNode(p_eval, operand_id); \ + if(!p_result_node) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; \ + goto CLEANUP; \ + } \ +} + +#define EVALUATE_OPERAND(p_result_node, res, CLEANUP) \ +{ \ + res = EvaluateResult_Do(p_result_node); \ + if (res != SPV_REFLECT_RESULT_SUCCESS) goto CLEANUP;\ } #define SIMPLE_UNARY_OP_32_BIT_HOOK #define SIMPLE_UNARY_OP_64_BIT_HOOK -#define DO_SIMPLE_UNARY_INTEGER_OPERATION(p_result, simple_op_eval, simple_op_node, res, CLEANUP) \ +#define DO_SIMPLE_UNARY_INTEGER_OPERATION(simple_op_eval, p_node, res, CLEANUP) \ { \ - CHECK_INSTRUCTION_SIZE((simple_op_node), 5) \ - \ - /* check result type */ \ - CHECK_IS_INTEGER_TYPE((p_result), res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE((p_result), res, CLEANUP) \ - \ - /* get operand */ \ - SpvReflectValue* operand1 = NULL; \ - GET_OPERAND((simple_op_eval), (simple_op_node), 4, operand1, res, CLEANUP) \ - /* check type here */ \ - CHECK_IS_INTEGER_TYPE(operand1, res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) \ - \ - /* component width must match. */ \ - CHECK_WIDTH_MATCH((p_result), operand1, res, CLEANUP) \ - \ - /* vector size must match */ \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, (p_result), operand1, res, CLEANUP) \ - \ - /* now do the job */ \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - (p_result)->data.numeric.vector.value[i].undefined_value \ - = operand1->data.numeric.vector.value[i].undefined_value; \ - switch (operand1->type->traits.numeric.scalar.width) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - case 32: \ - /* 32 bit integer */ \ - { \ - int32_t data = operand1->data.numeric.vector.value[i].value.sint32_value; \ - SIMPLE_UNARY_OP_32_BIT_HOOK \ - (p_result)->data.numeric.vector.value[i].value.sint32_value = data; \ - } \ - break; \ - case 64: \ - /* 64 bit integer */ \ - { \ - int64_t data = operand1->data.numeric.vector.value[i].value.sint64_value; \ - SIMPLE_UNARY_OP_64_BIT_HOOK \ - (p_result)->data.numeric.vector.value[i].value.sint64_value = data; \ - } \ - break; \ - } \ - } \ + switch (evaluation_mode) { \ + default: \ + {\ + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR;\ + goto CLEANUP;\ + }\ + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL:\ + {\ + uint32_t vec_size = 1;\ + if (p_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) {\ + vec_size = p_node->value.type->traits.numeric.vector.component_count;\ + }\ + SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0];\ + EVALUATE_OPERAND(operand1, res, CLEANUP)\ + \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + p_node->value.data.numeric.vector.value[i].undefined_value \ + = operand1->value.data.numeric.vector.value[i].undefined_value; \ + switch (operand1->value.type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + /* 32 bit integer */ \ + { \ + int32_t data = operand1->value.data.numeric.vector.value[i].value.sint32_value; \ + SIMPLE_UNARY_OP_32_BIT_HOOK \ + p_node->value.data.numeric.vector.value[i].value.sint32_value = data; \ + } \ + break; \ + case 64: \ + /* 64 bit integer */ \ + { \ + int64_t data = operand1->value.data.numeric.vector.value[i].value.sint64_value; \ + SIMPLE_UNARY_OP_64_BIT_HOOK \ + p_node->value.data.numeric.vector.value[i].value.sint64_value = data; \ + } \ + break; \ + } \ + } \ + } \ + break;\ + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS:\ + {\ + CHECK_INSTRUCTION_SIZE(p_node, 5)\ + p_node->num_id_operands = 1;\ + p_node->num_literal_words = 0;\ + \ + /* check result type */\ + CHECK_IS_INTEGER_TYPE(p_node, res, CLEANUP)\ + CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP)\ + }\ + break;\ + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS:\ + {\ + GET_OPERAND((simple_op_eval), p_node, 4, p_node->id_operands[0], res, CLEANUP)\ + CHECK_IS_INTEGER_TYPE(p_node->id_operands[0], res, CLEANUP)\ + CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP)\ + CHECK_WIDTH_MATCH(p_node, p_node->id_operands[0], res, CLEANUP)\ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_node, p_node->id_operands[0], res, CLEANUP)\ + }\ + break;\ + }\ } #define SIMPLE_BINARY_OP_32_BIT_HOOK #define SIMPLE_BINARY_OP_64_BIT_HOOK - -#define DO_SIMPLE_BINARY_INTEGER_OPERATION(p_result, simple_op_eval, simple_op_node, operation, res, CLEANUP) \ +#define DO_SIMPLE_BINARY_INTEGER_OPERATION(simple_op_eval, simple_op_node, operation, res, CLEANUP) \ +{ \ + switch (evaluation_mode) { \ + default: \ + {\ + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR;\ + goto CLEANUP;\ + }\ + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL:\ + {\ + uint32_t vec_size = 1;\ + if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) {\ + vec_size = simple_op_node->value.type->traits.numeric.vector.component_count;\ + }\ + SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0];\ + SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1];\ + EVALUATE_OPERAND(operand1, res, CLEANUP)\ + EVALUATE_OPERAND(operand2, res, CLEANUP)\ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->value.data.numeric.vector.value[i].undefined_value \ + || operand2->value.data.numeric.vector.value[i].undefined_value) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + switch ((simple_op_node)->value.type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + { \ + /* load data into int32_t*/ \ + int32_t data1 = operand1->value.data.numeric.vector.value[i].value.sint32_value; \ + int32_t data2 = operand2->value.data.numeric.vector.value[i].value.sint32_value; \ + int32_t data = data1 operation data2; \ + SIMPLE_BINARY_OP_32_BIT_HOOK \ + /* write to correct offset */ \ + (simple_op_node)->value.data.numeric.vector.value[i].value.sint32_value = data; \ + } \ + break; \ + case 64: \ + { \ + /* load data into int64_t*/ \ + int64_t data1 = operand1->value.data.numeric.vector.value[i].value.sint64_value; \ + int64_t data2 = operand2->value.data.numeric.vector.value[i].value.sint64_value; \ + int64_t data = data1 operation data2; \ + SIMPLE_BINARY_OP_32_BIT_HOOK \ + /* write to correct offset */ \ + (simple_op_node)->value.data.numeric.vector.value[i].value.sint64_value = data; \ + } \ + break; \ + } \ + }\ + }\ + break;\ + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS:\ + {\ + CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ + simple_op_node->num_id_operands = 2;\ + simple_op_node->num_literal_words = 0;\ + \ + /* check result type */\ + CHECK_IS_INTEGER_TYPE(simple_op_node, res, CLEANUP)\ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node, res, CLEANUP)\ + }\ + break;\ + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS:\ + {\ + GET_OPERAND((simple_op_eval), simple_op_node, 4, p_node->id_operands[0], res, CLEANUP)\ + CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[0], res, CLEANUP)\ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP)\ + GET_OPERAND((simple_op_eval), p_node, 5, p_node->id_operands[1], res, CLEANUP)\ + CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[1], res, CLEANUP)\ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP)\ + \ + /* check agains result */\ + CHECK_WIDTH_MATCH(simple_op_node, p_node->id_operands[0], res, CLEANUP)\ + CHECK_WIDTH_MATCH(simple_op_node, p_node->id_operands[1], res, CLEANUP)\ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP)\ + }\ + break;\ + }\ +} + +#define DO_UNSIGNED_INTEGER_DIVISION(simple_op_eval, simple_op_node, operation, res, CLEANUP) \ { \ - { \ - CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ - /* check result type*/ \ - CHECK_IS_INTEGER_TYPE(p_result, res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE((p_result), res, CLEANUP) \ - \ - /* get operand */ \ - SpvReflectValue* operand1 = NULL; \ - GET_OPERAND(simple_op_eval, simple_op_node, 4, operand1, res, CLEANUP) \ - CHECK_IS_INTEGER_TYPE(operand1, res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) \ - \ - SpvReflectValue* operand2 = NULL; \ - GET_OPERAND(simple_op_eval, simple_op_node, 5, operand2, res, CLEANUP) \ - CHECK_IS_INTEGER_TYPE(operand2, res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(operand2, res, CLEANUP) \ - \ - /* component width must be same */ \ - CHECK_WIDTH_MATCH(p_result, operand1, res, CLEANUP) \ - CHECK_WIDTH_MATCH(p_result, operand2, res, CLEANUP) \ - \ - /* vectors must be of same size */ \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), operand1, operand2, res, CLEANUP) \ - /* now do the job, width unknown but same, all three sign unkown \ - but still, since spv defines signed integer as 2-compliment, \ - so do recent c/cpp standard, directly adding uint should be enough.*/ \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1->data.numeric.vector.value[i].undefined_value \ - || operand2->data.numeric.vector.value[i].undefined_value) { \ - (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ - } \ - switch ((p_result)->type->traits.numeric.scalar.width) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - case 32: \ - { \ - /* load data into int32_t*/ \ - int32_t data1 = operand1->data.numeric.vector.value[i].value.sint32_value; \ - int32_t data2 = operand2->data.numeric.vector.value[i].value.sint32_value; \ - int32_t data = data1 operation data2; \ - SIMPLE_BINARY_OP_32_BIT_HOOK \ - /* write to correct offset */ \ - (p_result)->data.numeric.vector.value[i].value.sint32_value = data; \ - } \ - break; \ - case 64: \ - { \ - /* load data into int64_t*/ \ - int64_t data1 = operand1->data.numeric.vector.value[i].value.sint64_value; \ - int64_t data2 = operand2->data.numeric.vector.value[i].value.sint64_value; \ - int64_t data = data1 operation data2; \ - SIMPLE_BINARY_OP_32_BIT_HOOK \ - /* write to correct offset */ \ - (p_result)->data.numeric.vector.value[i].value.sint64_value = data; \ - } \ - break; \ - } \ - } \ - } \ -} - -#define DO_UNSIGNED_INTEGER_DIVISION(p_result, simple_op_eval, simple_op_node, operation, res, CLEANUP) \ -{ \ - CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ - /* check result type */ \ - CHECK_IS_INTEGER_TYPE(p_result, res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(p_result, res, CLEANUP) \ - if ((p_result)->type->traits.numeric.scalar.signedness) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - \ - /* get operand */ \ - SpvReflectValue* operand1 = NULL; \ - GET_OPERAND(simple_op_eval, simple_op_node, 4, operand1, res, CLEANUP) \ - if ((!operand1->type) || operand1->type->id != (p_result)->type->id) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - SpvReflectValue* operand2 = NULL; \ - GET_OPERAND(simple_op_eval, simple_op_node, 5, operand2, res, CLEANUP) \ - if ((!operand2->type) || operand2->type->id != (p_result)->type->id) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), operand1, operand2, res, CLEANUP) \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1->data.numeric.vector.value[i].undefined_value \ - || operand2->data.numeric.vector.value[i].undefined_value) { \ - (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ - } \ - switch ((p_result)->type->traits.numeric.scalar.width) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - case 32: \ - { \ - (p_result)->data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1->data.numeric.vector.value[i].value.uint32_bool_value \ - operation operand2->data.numeric.vector.value[i].value.uint32_bool_value; \ - if (operand2->data.numeric.vector.value[i].value.uint32_bool_value == 0) { \ - (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ - } \ - } \ - break; \ - case 64: \ - { \ - (p_result)->data.numeric.vector.value[i].value.uint64_value \ - = operand1->data.numeric.vector.value[i].value.uint64_value \ - operation operand2->data.numeric.vector.value[i].value.uint64_value; \ - if (operand2->data.numeric.vector.value[i].value.uint64_value == 0) { \ - (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ - } \ - } \ - break; \ - } \ - } \ + switch (evaluation_mode) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR;\ + goto CLEANUP;\ + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL:\ + {\ + uint32_t vec_size = 1;\ + if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) {\ + vec_size = simple_op_node->value.type->traits.numeric.vector.component_count;\ + }\ + SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0];\ + SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1];\ + EVALUATE_OPERAND(operand1, res, CLEANUP)\ + EVALUATE_OPERAND(operand2, res, CLEANUP)\ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->value.data.numeric.vector.value[i].undefined_value \ + || operand2->value.data.numeric.vector.value[i].undefined_value) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + switch ((simple_op_node)->value.type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + { \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value \ + operation operand2->value.data.numeric.vector.value[i].value.uint32_bool_value; \ + if (operand2->value.data.numeric.vector.value[i].value.uint32_bool_value == 0) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + } \ + break; \ + case 64: \ + { \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint64_value \ + = operand1->value.data.numeric.vector.value[i].value.uint64_value \ + operation operand2->value.data.numeric.vector.value[i].value.uint64_value; \ + if (operand2->value.data.numeric.vector.value[i].value.uint64_value == 0) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + } \ + break; \ + } \ + } \ + }\ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS:\ + {\ + CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ + simple_op_node->num_id_operands = 2;\ + simple_op_node->num_literal_words = 0;\ + \ + /* check result type */\ + CHECK_IS_INTEGER_TYPE(simple_op_node, res, CLEANUP)\ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node, res, CLEANUP)\ + if ((simple_op_node)->value.type->traits.numeric.scalar.signedness) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + }\ + break;\ + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS:\ + {\ + GET_OPERAND((simple_op_eval), simple_op_node, 4, simple_op_node->id_operands[0], res, CLEANUP)\ + if(p_node->id_operands[0]->value.type->id != p_node->value.type->id) {\ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE;\ + goto CLEANUP;\ + }\ + GET_OPERAND((simple_op_eval), simple_op_node, 5, simple_op_node->id_operands[1], res, CLEANUP)\ + if(p_node->id_operands[1]->value.type->id != p_node->value.type->id) {\ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE;\ + goto CLEANUP;\ + }\ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP)\ + }\ + break;\ + }\ } #define SHIFT_OP_32_BIT_HOOK_PRE @@ -5889,232 +5951,361 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect #define SHIFT_OP_32_BIT_HOOK_POST #define SHIFT_OP_64_BIT_HOOK_POST -#define DO_SHIFT_OPERATION(p_result, simple_op_eval, simple_op_node, operation, res, CLEANUP) \ -{ \ - CHECK_INSTRUCTION_SIZE((simple_op_node), 6) \ - /* check result type */ \ - CHECK_IS_INTEGER_TYPE((p_result), res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(p_result, res, CLEANUP) \ - \ - /* get operand */ \ - SpvReflectValue* operand1 = NULL; \ - GET_OPERAND((simple_op_eval), (simple_op_node), 4, operand1, res, CLEANUP) \ - CHECK_IS_INTEGER_TYPE(operand1, res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) \ - \ - SpvReflectValue* operand2 = NULL; \ - GET_OPERAND((simple_op_eval), (simple_op_node), 5, operand2, res, CLEANUP) \ - CHECK_IS_INTEGER_TYPE(operand2, res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(operand2, res, CLEANUP) \ - \ - /* op1 and result must have same width */ \ - CHECK_WIDTH_MATCH((p_result), operand1, res, CLEANUP) \ - uint32_t res_width = (p_result)->type->traits.numeric.scalar.width; \ - \ - /* vectors must be of same size */ \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), operand1, operand2, res, CLEANUP) \ - \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1->data.numeric.vector.value[i].undefined_value \ - || operand2->data.numeric.vector.value[i].undefined_value) { \ - (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ - } \ - /* load the shift number, set undefined flag if larger than result width*/ \ - uint8_t shift_num; \ - switch (operand2->type->traits.numeric.scalar.width) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - case 32: \ - { \ - uint32_t shift = operand2->data.numeric.vector.value[i].value.uint32_bool_value; \ - if (operand1->data.numeric.vector.value[i].undefined_value || shift >= res_width) { \ - (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ - } \ - shift_num = (uint8_t)shift; \ - } \ - break; \ - case 64: \ - { \ - uint64_t shift = operand2->data.numeric.vector.value[i].value.uint64_value; \ - if (operand1->data.numeric.vector.value[i].undefined_value || shift >= res_width) { \ - (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ - } \ - shift_num = (uint8_t)shift; \ - } \ - break; \ - } \ - switch (res_width) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - case 32: \ - { \ - uint32_t data = operand1->data.numeric.vector.value[i].value.uint32_bool_value; \ - SHIFT_OP_32_BIT_HOOK_PRE \ - data operation##= shift_num; \ - SHIFT_OP_32_BIT_HOOK_POST \ - (p_result)->data.numeric.vector.value[i].value.uint32_bool_value = data; \ - } \ - break; \ - case 64: \ - { \ - uint64_t data = operand1->data.numeric.vector.value[i].value.uint64_value; \ - SHIFT_OP_64_BIT_HOOK_PRE \ - data operation##= shift_num; \ - SHIFT_OP_64_BIT_HOOK_POST \ - (p_result)->data.numeric.vector.value[i].value.uint64_value = data; \ - } \ - break; \ - } \ - } \ -} - -#define DO_BINARY_BOOLEAN_LOGICAL_OPERATION(p_result, simple_op_eval, simple_op_node, operation, res, CLEANUP) \ +#define DO_SHIFT_OPERATION(simple_op_eval, simple_op_node, operation, res, CLEANUP) \ +{ \ + switch (evaluation_mode) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR;\ + goto CLEANUP;\ + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL:\ + {\ + uint32_t vec_size = 1;\ + if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) {\ + vec_size = simple_op_node->value.type->traits.numeric.vector.component_count;\ + }\ + SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0];\ + SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1];\ + EVALUATE_OPERAND(operand1, res, CLEANUP)\ + EVALUATE_OPERAND(operand2, res, CLEANUP)\ + uint32_t res_width = (p_node)->value.type->traits.numeric.scalar.width;\ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->value.data.numeric.vector.value[i].undefined_value \ + || operand2->value.data.numeric.vector.value[i].undefined_value) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + /* load the shift number, set undefined flag if larger than result width*/ \ + uint8_t shift_num; \ + switch (operand2->value.type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + { \ + uint32_t shift = operand2->value.data.numeric.vector.value[i].value.uint32_bool_value; \ + if (operand1->value.data.numeric.vector.value[i].undefined_value || shift >= res_width) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + shift_num = (uint8_t)shift; \ + } \ + break; \ + case 64: \ + { \ + uint64_t shift = operand2->value.data.numeric.vector.value[i].value.uint64_value; \ + if (operand1->value.data.numeric.vector.value[i].undefined_value || shift >= res_width) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + shift_num = (uint8_t)shift; \ + } \ + break; \ + } \ + switch (res_width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + { \ + uint32_t data = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value; \ + SHIFT_OP_32_BIT_HOOK_PRE \ + data operation##= shift_num; \ + SHIFT_OP_32_BIT_HOOK_POST \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value = data; \ + } \ + break; \ + case 64: \ + { \ + uint64_t data = operand1->value.data.numeric.vector.value[i].value.uint64_value; \ + SHIFT_OP_64_BIT_HOOK_PRE \ + data operation##= shift_num; \ + SHIFT_OP_64_BIT_HOOK_POST \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint64_value = data; \ + } \ + break; \ + } \ + } \ + }\ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS:\ + {\ + CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ + simple_op_node->num_id_operands = 2;\ + simple_op_node->num_literal_words = 0;\ + \ + /* check result type */\ + CHECK_IS_INTEGER_TYPE(simple_op_node, res, CLEANUP)\ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node, res, CLEANUP)\ + }\ + break;\ + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS:\ + {\ + GET_OPERAND((simple_op_eval), simple_op_node, 4, p_node->id_operands[0], res, CLEANUP)\ + CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[0], res, CLEANUP)\ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP)\ + GET_OPERAND((simple_op_eval), p_node, 5, p_node->id_operands[1], res, CLEANUP)\ + CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[1], res, CLEANUP)\ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP)\ + \ + /* op1 and result must have same width */\ + CHECK_WIDTH_MATCH(simple_op_node, p_node->id_operands[0], res, CLEANUP)\ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP)\ + }\ + break;\ + }\ +} + +#define DO_BINARY_BOOLEAN_LOGICAL_OPERATION(simple_op_eval, simple_op_node, operation, res, CLEANUP) \ +{ \ + switch (evaluation_mode) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR;\ + goto CLEANUP;\ + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL:\ + {\ + uint32_t vec_size = 1;\ + if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) {\ + vec_size = simple_op_node->value.type->traits.numeric.vector.component_count;\ + }\ + SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0];\ + SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1];\ + EVALUATE_OPERAND(operand1, res, CLEANUP)\ + EVALUATE_OPERAND(operand2, res, CLEANUP)\ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->value.data.numeric.vector.value[i].undefined_value \ + operation operand2->value.data.numeric.vector.value[i].undefined_value) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + /* write to correct offset */ \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value \ + operation operand2->value.data.numeric.vector.value[i].value.uint32_bool_value; \ + } \ + }\ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS:\ + {\ + CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ + simple_op_node->num_id_operands = 2;\ + simple_op_node->num_literal_words = 0;\ + \ + /* check result type */\ + CHECK_IS_BOOLEAN_TYPE((simple_op_node), res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node), res, CLEANUP) \ + if ((simple_op_node)->value.type->traits.numeric.scalar.signedness) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + }\ + break;\ + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS:\ + {\ + GET_OPERAND((simple_op_eval), simple_op_node, 4, p_node->id_operands[0], res, CLEANUP)\ + CHECK_IS_BOOLEAN_TYPE(simple_op_node->id_operands[0], res, CLEANUP)\ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP)\ + GET_OPERAND((simple_op_eval), p_node, 5, p_node->id_operands[1], res, CLEANUP)\ + CHECK_IS_BOOLEAN_TYPE(simple_op_node->id_operands[1], res, CLEANUP)\ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP)\ + \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP)\ + }\ + break;\ + }\ +} + +#define DO_BINARY_INTEGER_LOGICAL_OPERATION(simple_op_eval, simple_op_node, operation, _32bit_member, _64bit_member, res, CLEANUP) \ { \ - CHECK_INSTRUCTION_SIZE((simple_op_node), 6) \ - \ - /* check result type */ \ - CHECK_IS_BOOLEAN_TYPE((p_result), res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE((p_result), res, CLEANUP) \ - \ - /* get operand */ \ - SpvReflectValue* operand1 = NULL; \ - GET_OPERAND((simple_op_eval), (simple_op_node), 4, operand1, res, CLEANUP) \ - CHECK_IS_BOOLEAN_TYPE(operand1, res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) \ - \ - SpvReflectValue* operand2 = NULL; \ - GET_OPERAND((simple_op_eval), (simple_op_node), 5, operand2, res, CLEANUP) \ - CHECK_IS_BOOLEAN_TYPE(operand2, res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(operand2, res, CLEANUP) \ - \ - /* vectors must be of same size */ \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), operand1, operand2, res, CLEANUP) \ - \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1->data.numeric.vector.value[i].undefined_value \ - operation operand2->data.numeric.vector.value[i].undefined_value) { \ - (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ - } \ - /* write to correct offset */ \ - (p_result)->data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1->data.numeric.vector.value[i].value.uint32_bool_value \ - operation operand2->data.numeric.vector.value[i].value.uint32_bool_value; \ - } \ -} - -#define DO_BINARY_INTEGER_LOGICAL_OPERATION(p_result, simple_op_eval, simple_op_node, operation, _32bit_member, _64bit_member, res, CLEANUP) \ -{ \ - CHECK_INSTRUCTION_SIZE((simple_op_node), 6) \ - \ - /* check result type */ \ - CHECK_IS_BOOLEAN_TYPE((p_result), res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE((p_result), res, CLEANUP) \ - \ - /* get operand */ \ - SpvReflectValue* operand1 = NULL; \ - GET_OPERAND((simple_op_eval), (simple_op_node), 4, operand1, res, CLEANUP) \ - CHECK_IS_INTEGER_TYPE(operand1, res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) \ - \ - SpvReflectValue* operand2 = NULL; \ - GET_OPERAND((simple_op_eval), (simple_op_node), 5, operand2, res, CLEANUP) \ - CHECK_IS_INTEGER_TYPE(operand2, res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(operand2, res, CLEANUP) \ - \ - /* vectors must be of same size */ \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (p_result), operand1, operand2, res, CLEANUP) \ - \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1->data.numeric.vector.value[i].undefined_value \ - || operand2->data.numeric.vector.value[i].undefined_value) { \ - (p_result)->data.numeric.vector.value[i].undefined_value = 1; \ - } \ - switch (operand1->type->traits.numeric.scalar.width) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - case 32: \ - (p_result)->data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1->data.numeric.vector.value[i].value.##_32bit_member \ - operation operand2->data.numeric.vector.value[i].value.##_32bit_member; \ - break; \ - case 64: \ - (p_result)->data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1->data.numeric.vector.value[i].value.##_64bit_member \ - operation operand2->data.numeric.vector.value[i].value.##_64bit_member; \ - break; \ - } \ - } \ -} - -#define DO_BINARY_UINTEGER_LOGICAL_OPERATION(p_result, simple_op_eval, simple_op_node, operation, res, CLEANUP) \ - DO_BINARY_INTEGER_LOGICAL_OPERATION(p_result, simple_op_eval, simple_op_node, operation, uint32_bool_value, uint64_value, res, CLEANUP) -#define DO_BINARY_SINTEGER_LOGICAL_OPERATION(p_result, simple_op_eval, simple_op_node, operation, res, CLEANUP) \ - DO_BINARY_INTEGER_LOGICAL_OPERATION(p_result, simple_op_eval, simple_op_node, operation, sint32_value, sint64_value, res, CLEANUP) - -// Used for calculating specialization constants. -// The switches are not necessary for littel endian cpu, -// but still there just in case. -// memcpy is required since c/c++ have strict aliasing rules -// access to signed and unsigned versions of same width integer's -// address does not violate strict aliasing rules -SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t result_id, const SpvReflectValue** p_result) + switch (evaluation_mode) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR;\ + goto CLEANUP;\ + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL:\ + {\ + uint32_t vec_size = 1;\ + if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) {\ + vec_size = simple_op_node->value.type->traits.numeric.vector.component_count;\ + }\ + SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0];\ + SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1];\ + EVALUATE_OPERAND(operand1, res, CLEANUP)\ + EVALUATE_OPERAND(operand2, res, CLEANUP)\ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->value.data.numeric.vector.value[i].undefined_value \ + || operand2->value.data.numeric.vector.value[i].undefined_value) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + switch (operand1->value.type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1->value.data.numeric.vector.value[i].value.##_32bit_member \ + operation operand2->value.data.numeric.vector.value[i].value.##_32bit_member; \ + break; \ + case 64: \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1->value.data.numeric.vector.value[i].value.##_64bit_member \ + operation operand2->value.data.numeric.vector.value[i].value.##_64bit_member; \ + break; \ + } \ + } \ + }\ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS:\ + {\ + CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ + simple_op_node->num_id_operands = 2;\ + simple_op_node->num_literal_words = 0;\ + \ + /* check result type */\ + CHECK_IS_BOOLEAN_TYPE((simple_op_node), res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node), res, CLEANUP) \ + if ((simple_op_node)->value.type->traits.numeric.scalar.signedness) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + }\ + break;\ + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS:\ + {\ + GET_OPERAND((simple_op_eval), simple_op_node, 4, p_node->id_operands[0], res, CLEANUP)\ + CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[0], res, CLEANUP)\ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP)\ + GET_OPERAND((simple_op_eval), p_node, 5, p_node->id_operands[1], res, CLEANUP)\ + CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[1], res, CLEANUP)\ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP)\ + \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP)\ + }\ + break;\ + }\ +} + +#define DO_BINARY_UINTEGER_LOGICAL_OPERATION(simple_op_eval, simple_op_node, operation, res, CLEANUP) \ + DO_BINARY_INTEGER_LOGICAL_OPERATION(simple_op_eval, simple_op_node, operation, uint32_bool_value, uint64_value, res, CLEANUP) +#define DO_BINARY_SINTEGER_LOGICAL_OPERATION(simple_op_eval, simple_op_node, operation, res, CLEANUP) \ + DO_BINARY_INTEGER_LOGICAL_OPERATION(simple_op_eval, simple_op_node, operation, sint32_value, sint64_value, res, CLEANUP) + + +#ifdef _MSC_VER +#define SPIRV_REFLECT_FORCEINLINE __forceinline +#else +#define SPIRV_REFLECT_FORCEINLINE __attribute__((always_inline)) inline +#endif + + +static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node, SpvReflectEvaluationState evaluation_mode); +static SpvReflectResult EvaluateResult_Do(SpvReflectPrvEvaluationNode* p_node) { + return EvaluateResultImpl(NULL, p_node, SPIRV_REFLECT_EVALUATION_MODE_NORMAL); +} +static SpvReflectResult EvaluateResult_1PASS(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node){ + return EvaluateResultImpl(p_eval, p_node, SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS); +} +static SpvReflectResult EvaluateResult_2PASS(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node) { + return EvaluateResultImpl(p_eval, p_node, SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS); +} + +// change implementation to use SpvReflectPrvEvaluationNode* and SpvReflectEvaluation* p_eval as the only two parameters +// node is the node to evaluate, p_eval != NULL signals AST building. 2 passes of ast building will be +// labeled in p_eval's flags +// This function should be inline, and outside should call the _1PASS, _2PASS, _EVAL versions, so compiler can +// remove the inner branches... +static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node, SpvReflectEvaluationState evaluation_mode) { + if (!p_node) return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + SpvReflectResult res = SPV_REFLECT_RESULT_SUCCESS; - SpvReflectPrvEvaluationNode* p_node = FindEvaluationNode(p_eval, result_id); - if (!p_node) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; - *p_result = &p_node->value; + switch (evaluation_mode) { + default: + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED; + return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + switch(p_node->evaluation_state){ + case SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED: + return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + case SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED: + return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + case SPV_REFLECT_EVALUATION_NODE_STATE_PENDING: + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_WORKING; + break; + case SPV_REFLECT_EVALUATION_NODE_STATE_WORKING: + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_FAILED; + return SPV_REFLECT_RESULT_ERROR_SPIRV_RECURSION; + case SPV_REFLECT_EVALUATION_NODE_STATE_DONE: + return SPV_REFLECT_RESULT_SUCCESS; + case SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED: + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_WORKING; + break; + case SPV_REFLECT_EVALUATION_NODE_STATE_FAILED: + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + switch (p_node->evaluation_state) { + case SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED: + break; + case SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED: + return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + case SPV_REFLECT_EVALUATION_NODE_STATE_PENDING: + case SPV_REFLECT_EVALUATION_NODE_STATE_WORKING: + case SPV_REFLECT_EVALUATION_NODE_STATE_DONE: + case SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED: + case SPV_REFLECT_EVALUATION_NODE_STATE_FAILED: + return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { + switch (p_node->evaluation_state) { + case SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED: + break; + case SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED: + return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + case SPV_REFLECT_EVALUATION_NODE_STATE_PENDING: + case SPV_REFLECT_EVALUATION_NODE_STATE_WORKING: + case SPV_REFLECT_EVALUATION_NODE_STATE_DONE: + case SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED: + case SPV_REFLECT_EVALUATION_NODE_STATE_FAILED: + return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + } + } + break; + } + SpvReflectValue* result = &p_node->value; if (!result->type) { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; } - if (p_node->evaluation_state == SPV_REFLECT_EVALUATION_STATE_FAILED) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; - } - if (p_node->evaluation_state == SPV_REFLECT_EVALUATION_STATE_WORKING) { - p_node->evaluation_state = SPV_REFLECT_EVALUATION_STATE_FAILED; - return SPV_REFLECT_RESULT_ERROR_SPIRV_RECURSION; - } - if (p_node->evaluation_state == SPV_REFLECT_EVALUATION_STATE_DONE) { - return SPV_REFLECT_RESULT_SUCCESS; - } - uint32_t orig_state = p_node->evaluation_state; - p_node->evaluation_state = SPV_REFLECT_EVALUATION_STATE_WORKING; switch (p_node->op) { default: res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; break; - case SpvOpConstantTrue: - { - result->data.numeric.scalar.value.uint32_bool_value = 1; - } - break; - case SpvOpConstantFalse: - { - result->data.numeric.scalar.value.uint32_bool_value = 0; - } - break; + case SpvOpConstantTrue: case SpvOpConstantFalse: case SpvOpConstant: - CONSTANT_RESULT: - res = EvalGetScalarConstant(p_eval, p_node); - break; case SpvOpSpecConstantTrue: case SpvOpSpecConstantFalse: case SpvOpSpecConstant: - { - if (p_node->specId == INVALID_VALUE) { - goto CONSTANT_RESULT; - } - if (orig_state != SPV_REFLECT_EVALUATION_STATE_DONE && orig_state != SPV_REFLECT_EVALUATION_STATE_UPDATED) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; - goto CLEANUP; - } - // no need to do anything... + switch (evaluation_mode) { + default: + { + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + } + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + p_node->num_id_operands = 0; + p_node->num_literal_words = 0; + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + break; } break; case SpvOpSpecConstantComposite: @@ -6122,31 +6313,55 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul // only support compositing vector types for now... // vectors are needed for spv compiled to WorkgroupSize builtin // in expressing actual localsize - - // compositing types if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; goto CLEANUP; } - uint32_t vec_size = 1; - // should always have, since scalars do not need composite - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - vec_size = result->type->traits.numeric.vector.component_count; - } - // check instruction size - if (p_node->word_count != 3 + vec_size) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; - goto CLEANUP; - } - for (uint32_t i = 0; i < vec_size; ++i) { - SpvReflectValue* operandi = NULL; - GET_OPERAND(p_eval, p_node, 3 + i, operandi, res, CLEANUP); - // check type compatibility - if (operandi->type->type_flags & SCALAR_DISALLOWED_FLAGS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - result->data.numeric.vector.value[i] = operandi->data.numeric.scalar; + switch (evaluation_mode) { + default: + { + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + } + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + for (uint32_t i = 0; i < p_node->num_id_operands; ++i) { + result->data.numeric.vector.value[i] = p_node->id_operands[i]->value.data.numeric.scalar; + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + p_node->num_literal_words = 0; + uint32_t vec_size = 1; + // should always have, since scalars do not need composite + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + vec_size = result->type->traits.numeric.vector.component_count; + } + // other types here? + if (vec_size == 1) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + // check instruction size + if (p_node->word_count != 3 + vec_size) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + goto CLEANUP; + } + p_node->num_id_operands = vec_size; + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { + for (uint32_t i = 0; i < p_node->num_id_operands; ++i) { + GET_OPERAND(p_eval, p_node, 3 + i, p_node->id_operands[i], res, CLEANUP) + // check type compatibility + if (p_node->id_operands[i]->value.type->id != p_node->value.type->component_type_id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + } + } + break; } } break; @@ -6161,30 +6376,48 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; goto CLEANUP; } - - // evaluate op - uint32_t spec_op; - EVAL_CHECKED_READU32(p_eval, p_node->word_offset + 3, spec_op, res, CLEANUP); - switch (spec_op) { + if (evaluation_mode == SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS) { + EVAL_CHECKED_READU32(p_eval, p_node->word_offset + 3, p_node->specOp, res, CLEANUP); + } + + switch (p_node->specOp) { default: res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; goto CLEANUP; case SpvOpUndef: // write undefined value to result... { - CHECK_INSTRUCTION_SIZE(p_node, 4) - // all types allowed except void - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VOID) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - for (uint32_t i = 0; i < result->type->traits.numeric.vector.component_count; ++i) { - result->data.numeric.vector.value[i].undefined_value = 1; - } - } - else { - result->data.numeric.scalar.undefined_value = 1; + switch (evaluation_mode) { + default: + { + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + } + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + for (uint32_t i = 0; i < result->type->traits.numeric.vector.component_count; ++i) { + result->data.numeric.vector.value[i].undefined_value = 1; + } + } + else { + result->data.numeric.scalar.undefined_value = 1; + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + CHECK_INSTRUCTION_SIZE(p_node, 4) + p_node->num_id_operands = 0; + p_node->num_literal_words = 0; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VOID) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + break; } } break; @@ -6193,67 +6426,88 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul // result is scalar or vector integer type. // vectors should be of same length { - CHECK_INSTRUCTION_SIZE(p_node, 5) - - // check result type - CHECK_IS_INTEGER_TYPE(result, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(result, res, CLEANUP) - - // get operand - SpvReflectValue* operand1 = NULL; - GET_OPERAND(p_eval, p_node, 4, operand1, res, CLEANUP) - CHECK_IS_INTEGER_TYPE(operand1, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) - - // operand must be signed - if (!operand1->type->traits.numeric.scalar.signedness) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - // vector size must match - uint32_t vec_size = 1; - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, result, operand1, res, CLEANUP) - - // now do the job - for (uint32_t i = 0; i < vec_size; ++i) { - result->data.numeric.vector.value[i].undefined_value = operand1->data.numeric.vector.value[i].undefined_value; - switch (operand1->type->traits.numeric.scalar.width) { - default: - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + switch (evaluation_mode) { + default: + { + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; goto CLEANUP; - case 32: - { - int32_t data = operand1->data.numeric.vector.value[i].value.sint32_value; - switch (result->type->traits.numeric.scalar.width) { - default: - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - case 32: - result->data.numeric.vector.value[i].value.sint32_value = data; - break; - case 64: - result->data.numeric.vector.value[i].value.sint64_value = (int64_t)data; - break; - } + } + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + vec_size = result->type->traits.numeric.vector.component_count; } - break; - case 64: - { - int64_t data = operand1->data.numeric.vector.value[i].value.sint64_value; - switch (result->type->traits.numeric.scalar.width) { - default: + SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; + EVALUATE_OPERAND(operand1, res, CLEANUP) + for (uint32_t i = 0; i < vec_size; ++i) { + result->data.numeric.vector.value[i].undefined_value = operand1->value.data.numeric.vector.value[i].undefined_value; + switch (operand1->value.type->traits.numeric.scalar.width) { + default: res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; case 32: - result->data.numeric.vector.value[i].value.sint32_value = (int32_t)data; + { + int32_t data = operand1->value.data.numeric.vector.value[i].value.sint32_value; + switch (result->type->traits.numeric.scalar.width) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + case 32: + result->data.numeric.vector.value[i].value.sint32_value = data; + break; + case 64: + result->data.numeric.vector.value[i].value.sint64_value = (int64_t)data; + break; + } + } break; case 64: - result->data.numeric.vector.value[i].value.sint64_value = data; + { + int64_t data = operand1->value.data.numeric.vector.value[i].value.sint64_value; + switch (result->type->traits.numeric.scalar.width) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + case 32: + result->data.numeric.vector.value[i].value.sint32_value = (int32_t)data; + break; + case 64: + result->data.numeric.vector.value[i].value.sint64_value = data; + break; + } + } break; } } - break; - } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + CHECK_INSTRUCTION_SIZE(p_node, 5) + p_node->num_id_operands = 1; + p_node->num_literal_words = 0; + + // check result type + CHECK_IS_INTEGER_TYPE(p_node, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { + GET_OPERAND(p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) + CHECK_IS_INTEGER_TYPE(p_node->id_operands[0], res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) + + // operand must be signed + if (!p_node->id_operands[0]->value.type->traits.numeric.scalar.signedness) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + uint32_t vec_size = 1; + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_node, p_node->id_operands[0], res, CLEANUP) + } + break; } } break; @@ -6262,67 +6516,88 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul // result is scalar or vector integer type. // vectors should be of same length { - CHECK_INSTRUCTION_SIZE(p_node, 5) - - // check result type - CHECK_IS_INTEGER_TYPE(result, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(result, res, CLEANUP) - - // get operand - SpvReflectValue* operand1 = NULL; - GET_OPERAND(p_eval, p_node, 4, operand1, res, CLEANUP) - CHECK_IS_INTEGER_TYPE(operand1, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) - - // operand must not be signed - if (operand1->type->traits.numeric.scalar.signedness) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - // vector size must match - uint32_t vec_size = 1; - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, result, operand1, res, CLEANUP) - - // now do the job - for (uint32_t i = 0; i < vec_size; ++i) { - result->data.numeric.vector.value[i].undefined_value = operand1->data.numeric.vector.value[i].undefined_value; - switch (operand1->type->traits.numeric.scalar.width) { - default: - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + switch (evaluation_mode) { + default: + { + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; goto CLEANUP; - case 32: - { - uint32_t data = operand1->data.numeric.vector.value[i].value.uint32_bool_value; - switch (result->type->traits.numeric.scalar.width) { - default: - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - case 32: - result->data.numeric.vector.value[i].value.uint32_bool_value = data; - break; - case 64: - result->data.numeric.vector.value[i].value.uint64_value = (uint64_t)data; - break; - } + } + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + vec_size = result->type->traits.numeric.vector.component_count; } - break; - case 64: - { - uint64_t data = operand1->data.numeric.vector.value[i].value.uint64_value; - switch (result->type->traits.numeric.scalar.width) { - default: + SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; + EVALUATE_OPERAND(operand1, res, CLEANUP) + for (uint32_t i = 0; i < vec_size; ++i) { + result->data.numeric.vector.value[i].undefined_value = operand1->value.data.numeric.vector.value[i].undefined_value; + switch (operand1->value.type->traits.numeric.scalar.width) { + default: res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; case 32: - result->data.numeric.vector.value[i].value.uint32_bool_value = (uint32_t)data; + { + uint32_t data = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value; + switch (result->type->traits.numeric.scalar.width) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + case 32: + result->data.numeric.vector.value[i].value.uint32_bool_value = data; + break; + case 64: + result->data.numeric.vector.value[i].value.uint64_value = (uint64_t)data; + break; + } + } break; case 64: - result->data.numeric.vector.value[i].value.uint64_value = data; + { + uint64_t data = operand1->value.data.numeric.vector.value[i].value.uint64_value; + switch (result->type->traits.numeric.scalar.width) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + case 32: + result->data.numeric.vector.value[i].value.uint32_bool_value = (uint32_t)data; + break; + case 64: + result->data.numeric.vector.value[i].value.uint64_value = data; + break; + } + } break; } } - break; - } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + CHECK_INSTRUCTION_SIZE(p_node, 5) + p_node->num_id_operands = 1; + p_node->num_literal_words = 0; + + // check result type + CHECK_IS_INTEGER_TYPE(p_node, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { + GET_OPERAND(p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) + CHECK_IS_INTEGER_TYPE(p_node->id_operands[0], res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) + + // operand must be unsigned + if (p_node->id_operands[0]->value.type->traits.numeric.scalar.signedness) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + uint32_t vec_size = 1; + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_node, p_node->id_operands[0], res, CLEANUP) + } + break; } } break; @@ -6330,59 +6605,78 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul // convert of floating point integer to any integer of different width. // just 32 and 64 bit for now... { - CHECK_INSTRUCTION_SIZE(p_node, 5) - - // check result type - CHECK_IS_FLOAT_TYPE(result, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(result, res, CLEANUP) - - // get operand - SpvReflectValue* operand1 = NULL; - GET_OPERAND(p_eval, p_node, 4, operand1, res, CLEANUP) - - // check type here, remember undefined value and booleans with type == null - CHECK_IS_FLOAT_TYPE(operand1, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) - - // vector size must match - uint32_t vec_size = 1; - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, result, operand1, res, CLEANUP) - - // now do the job - for (uint32_t i = 0; i < vec_size; ++i) { - result->data.numeric.vector.value[i].undefined_value = operand1->data.numeric.vector.value[i].undefined_value; - switch (operand1->type->traits.numeric.scalar.width) { - default: - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - case 32: - // convert int32 to generic integer type - switch (result->type->traits.numeric.scalar.width) { - default: - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - case 32: - result->data.numeric.vector.value[i].value.float32_value = operand1->data.numeric.vector.value[i].value.float32_value; - break; - case 64: - result->data.numeric.vector.value[i].value.float64_value = (double)operand1->data.numeric.vector.value[i].value.float32_value; - break; + switch (evaluation_mode) { + default: + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + vec_size = result->type->traits.numeric.vector.component_count; } - break; - case 64: - // convert int64 to generic integer type - switch (result->type->traits.numeric.scalar.width) { - default: - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - case 32: - result->data.numeric.vector.value[i].value.float32_value = (float)operand1->data.numeric.vector.value[i].value.float64_value; - break; - case 64: - result->data.numeric.vector.value[i].value.float64_value = operand1->data.numeric.vector.value[i].value.float64_value; - break; + SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; + EVALUATE_OPERAND(operand1, res, CLEANUP) + // now do the job + for (uint32_t i = 0; i < vec_size; ++i) { + result->data.numeric.vector.value[i].undefined_value = operand1->value.data.numeric.vector.value[i].undefined_value; + switch (operand1->value.type->traits.numeric.scalar.width) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + case 32: + // convert int32 to generic integer type + switch (result->type->traits.numeric.scalar.width) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + case 32: + result->data.numeric.vector.value[i].value.float32_value = operand1->value.data.numeric.vector.value[i].value.float32_value; + break; + case 64: + result->data.numeric.vector.value[i].value.float64_value = (double)operand1->value.data.numeric.vector.value[i].value.float32_value; + break; + } + break; + case 64: + // convert int64 to generic integer type + switch (result->type->traits.numeric.scalar.width) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + case 32: + result->data.numeric.vector.value[i].value.float32_value = (float)operand1->value.data.numeric.vector.value[i].value.float64_value; + break; + case 64: + result->data.numeric.vector.value[i].value.float64_value = operand1->value.data.numeric.vector.value[i].value.float64_value; + break; + } + } } - } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + CHECK_INSTRUCTION_SIZE(p_node, 5) + p_node->num_id_operands = 1; + p_node->num_literal_words = 0; + + // check result type + CHECK_IS_FLOAT_TYPE(p_node, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { + GET_OPERAND(p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) + CHECK_IS_FLOAT_TYPE(p_node->id_operands[0], res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) + + // vector size must match + uint32_t vec_size = 1; + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_node, p_node->id_operands[0], res, CLEANUP) + } + break; } } break; @@ -6391,7 +6685,7 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul #undef SIMPLE_UNARY_OP_64_BIT_HOOK #define SIMPLE_UNARY_OP_32_BIT_HOOK {data = -data;} #define SIMPLE_UNARY_OP_64_BIT_HOOK {data = -data;} - DO_SIMPLE_UNARY_INTEGER_OPERATION(result, p_eval, p_node, res, CLEANUP) + DO_SIMPLE_UNARY_INTEGER_OPERATION(p_eval, p_node, res, CLEANUP) #undef SIMPLE_UNARY_OP_32_BIT_HOOK #undef SIMPLE_UNARY_OP_64_BIT_HOOK #define SIMPLE_UNARY_OP_32_BIT_HOOK @@ -6403,7 +6697,7 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul #undef SIMPLE_UNARY_OP_64_BIT_HOOK #define SIMPLE_UNARY_OP_32_BIT_HOOK data ^= 0xffffffff; #define SIMPLE_UNARY_OP_64_BIT_HOOK data ^= 0xffffffffffffffff; - DO_SIMPLE_UNARY_INTEGER_OPERATION(result, p_eval, p_node, res, CLEANUP) + DO_SIMPLE_UNARY_INTEGER_OPERATION(p_eval, p_node, res, CLEANUP) #undef SIMPLE_UNARY_OP_32_BIT_HOOK #undef SIMPLE_UNARY_OP_64_BIT_HOOK #define SIMPLE_UNARY_OP_32_BIT_HOOK @@ -6412,25 +6706,25 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul case SpvOpIAdd: // integer add. // subtraction result is the same for 2-compliment - DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_eval, p_node, +, res, CLEANUP) + DO_SIMPLE_BINARY_INTEGER_OPERATION(p_eval, p_node, +, res, CLEANUP) break; case SpvOpISub: // integer subtract. // subtraction result is the same for 2-compliment - DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_eval, p_node, -, res, CLEANUP) + DO_SIMPLE_BINARY_INTEGER_OPERATION(p_eval, p_node, -, res, CLEANUP) break; case SpvOpIMul: // integer multiply... // imul instruction on x86, signed and unsigned have no difference in result // except for how they overflow. - DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_eval, p_node, *, res, CLEANUP) + DO_SIMPLE_BINARY_INTEGER_OPERATION(p_eval, p_node, *, res, CLEANUP) break; case SpvOpUDiv: // unsigned divide // All operand must be same unsigned integer scalar or vector type. // x86 div instruction // emits undefined value if divide by zero - DO_UNSIGNED_INTEGER_DIVISION(result, p_eval, p_node, /, res, CLEANUP) + DO_UNSIGNED_INTEGER_DIVISION(p_eval, p_node, /, res, CLEANUP) break; case SpvOpSDiv: // signed divide @@ -6441,14 +6735,14 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul #undef SIMPLE_BINARY_OP_32_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ - result->data.numeric.vector.value[i].undefined_value = 1; \ + p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ } #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_64_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ - result->data.numeric.vector.value[i].undefined_value = 1; \ + p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ } - DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_eval, p_node, /, res, CLEANUP) + DO_SIMPLE_BINARY_INTEGER_OPERATION(p_eval, p_node, /, res, CLEANUP) #undef SIMPLE_BINARY_OP_32_BIT_HOOK #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK @@ -6457,21 +6751,21 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul case SpvOpUMod: // unsigned modulo // all types must be same unsigned integer scalar or vector type. - DO_UNSIGNED_INTEGER_DIVISION(result, p_eval, p_node, %, res, CLEANUP) + DO_UNSIGNED_INTEGER_DIVISION( p_eval, p_node, %, res, CLEANUP) break; case SpvOpSRem: // just the result of % operator. #undef SIMPLE_BINARY_OP_32_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ - result->data.numeric.vector.value[i].undefined_value = 1; \ + p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ } #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_64_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ - result->data.numeric.vector.value[i].undefined_value = 1; \ + p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ } - DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_eval, p_node, %, res, CLEANUP) + DO_SIMPLE_BINARY_INTEGER_OPERATION(p_eval, p_node, %, res, CLEANUP) #undef SIMPLE_BINARY_OP_32_BIT_HOOK #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK @@ -6482,7 +6776,7 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul #undef SIMPLE_BINARY_OP_32_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ - result->data.numeric.vector.value[i].undefined_value = 1; \ + p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ } \ else if (data != 0) { \ int sign1 = 0, sign2 = 0; \ @@ -6496,7 +6790,7 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_64_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ - result->data.numeric.vector.value[i].undefined_value = 1; \ + p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ } \ else if (data != 0) { \ int sign1 = 0, sign2 = 0; \ @@ -6507,7 +6801,7 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul data += data2; \ } \ } - DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_eval, p_node, %, res, CLEANUP) + DO_SIMPLE_BINARY_INTEGER_OPERATION(p_eval, p_node, %, res, CLEANUP) #undef SIMPLE_BINARY_OP_32_BIT_HOOK #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK @@ -6515,7 +6809,7 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul break; case SpvOpShiftRightLogical: // zero fill right shift. Just >> in c - DO_SHIFT_OPERATION(result, p_eval, p_node, >>, res, CLEANUP) + DO_SHIFT_OPERATION(p_eval, p_node, >>, res, CLEANUP) break; case SpvOpShiftRightArithmetic: // fill with sign of original number. @@ -6535,7 +6829,7 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul uint64_t fill = 0xffffffffffffffff << (64 - shift_num); \ data |= fill; \ } - DO_SHIFT_OPERATION(result, p_eval, p_node, >> , res, CLEANUP) + DO_SHIFT_OPERATION(p_eval, p_node, >> , res, CLEANUP) #undef SHIFT_OP_32_BIT_HOOK_PRE #undef SHIFT_OP_64_BIT_HOOK_PRE #undef SHIFT_OP_32_BIT_HOOK_POST @@ -6547,356 +6841,479 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul break; case SpvOpShiftLeftLogical: // zero fill left shift. Just << in c - DO_SHIFT_OPERATION(result, p_eval, p_node, << , res, CLEANUP) + DO_SHIFT_OPERATION(p_eval, p_node, << , res, CLEANUP) break; case SpvOpBitwiseOr: - DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_eval, p_node, |, res, CLEANUP) + DO_SIMPLE_BINARY_INTEGER_OPERATION(p_eval, p_node, |, res, CLEANUP) break; case SpvOpBitwiseXor: - DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_eval, p_node, ^ , res, CLEANUP) + DO_SIMPLE_BINARY_INTEGER_OPERATION(p_eval, p_node, ^ , res, CLEANUP) break; case SpvOpBitwiseAnd: - DO_SIMPLE_BINARY_INTEGER_OPERATION(result, p_eval, p_node, & , res, CLEANUP) + DO_SIMPLE_BINARY_INTEGER_OPERATION(p_eval, p_node, & , res, CLEANUP) break; case SpvOpVectorShuffle: { - /* check result type*/ - CHECK_IS_INTEGER_TYPE(result, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(result, res, CLEANUP) - if (!(result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } + switch (evaluation_mode) { + default: + { + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + } + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; + SpvReflectPrvEvaluationNode* operand2 = p_node->id_operands[1]; + EVALUATE_OPERAND(operand1, res, CLEANUP) + EVALUATE_OPERAND(operand2, res, CLEANUP) + for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { + uint32_t mapped_component = p_node->literal_words[i]; + if (mapped_component == 0xFFFFFFFF) { + result->data.numeric.vector.value[i].undefined_value = 1; + } + else if (mapped_component >= operand1->value.type->traits.numeric.vector.component_count + operand2->value.type->traits.numeric.vector.component_count) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + goto CLEANUP; + } + else if (mapped_component < operand1->value.type->traits.numeric.vector.component_count) { + result->data.numeric.vector.value[i] = operand1->value.data.numeric.vector.value[mapped_component]; + } + else { + result->data.numeric.vector.value[i] = operand2->value.data.numeric.vector.value[mapped_component - operand1->value.type->traits.numeric.vector.component_count]; + } + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + CHECK_IS_INTEGER_TYPE(p_node, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) + if (!(result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } - SpvReflectValue* operand1 = NULL; - GET_OPERAND((p_eval), (p_node), 4, operand1, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) - if (!(operand1->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - if (operand1->type->component_type_id != result->type->component_type_id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } + CHECK_INSTRUCTION_SIZE(p_node, 6 + p_node->value.type->traits.numeric.vector.component_count) - // cannot skip if type comes with result... - SpvReflectValue* operand2 = NULL; - GET_OPERAND((p_eval), (p_node), 5, operand2, res, CLEANUP) - if (!(operand2->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - if (operand2->type->component_type_id != result->type->component_type_id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } + p_node->num_id_operands = 2; + p_node->num_literal_words = p_node->value.type->traits.numeric.vector.component_count; - // instruction size must be: - // OpSpecConstantOp result_type result_id VectorShuffle vec1 vec2 comp1 comp2 .... - CHECK_INSTRUCTION_SIZE(p_node, 6 + result->type->traits.numeric.vector.component_count) + // check result type + CHECK_IS_FLOAT_TYPE(p_node, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { + GET_OPERAND(p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) + if (!(p_node->id_operands[0]->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + if(p_node->id_operands[0]->value.type->component_type_id != p_node->value.type->component_type_id){ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } - // now do the job... - for (uint32_t i = 0; i < result->type->traits.numeric.vector.component_count; ++i) { - uint32_t mapped_component; - EVAL_CHECKED_READU32(p_eval, p_node->word_offset + 6 + i, mapped_component, res, CLEANUP) - if (mapped_component == 0xFFFFFFFF) { - result->data.numeric.vector.value[i].undefined_value = 1; - } - else if (mapped_component >= operand1->type->traits.numeric.vector.component_count + operand2->type->traits.numeric.vector.component_count) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; - goto CLEANUP; - } - else if (mapped_component < operand1->type->traits.numeric.vector.component_count) { - result->data.numeric.vector.value[i] = operand1->data.numeric.vector.value[mapped_component]; - } - else { - result->data.numeric.vector.value[i] = operand2->data.numeric.vector.value[mapped_component - operand1->type->traits.numeric.vector.component_count]; - } + GET_OPERAND(p_eval,p_node, 5, p_node->id_operands[1], res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[1], res, CLEANUP) + if (!(p_node->id_operands[1]->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + if(p_node->id_operands[1]->value.type->component_type_id != p_node->value.type->component_type_id){ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + + for(uint32_t i = 0; inum_literal_words; ++i) { + EVAL_CHECKED_READU32(p_eval, p_node->word_offset + 6 + i, p_node->literal_words[i], res, CLEANUP); + } + } + break; } } break; - // only support vector types for now... + case SpvOpCompositeExtract: + // only support vector types for now... { - // check composite allowed flags - if (result->type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - // need to travers the composite tree down to last operand. - // currently only support vector composite type. + switch (evaluation_mode) { + default: + { + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + } + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + EVALUATE_OPERAND(p_node->id_operands[0], res, CLEANUP) + SpvReflectValueData* current_data = &p_node->id_operands[0]->value.data; + SpvReflectTypeDescription* current_type = p_node->id_operands[0]->value.type; + for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { + uint32_t member_index = p_node->literal_words[i]; + res = GetMemberByIndex(p_eval->member_type_finder, current_data, current_type, member_index, ¤t_data, ¤t_type); + if (res != SPV_REFLECT_RESULT_SUCCESS) { + goto CLEANUP; + } + } + if (current_type->id != p_node->value.type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + res = CopyValueData(current_type, &result->data, current_data); + if (res != SPV_REFLECT_RESULT_SUCCESS) { + goto CLEANUP; + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + if (p_node->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } - SpvReflectValue* operand1 = NULL; - GET_OPERAND((p_eval), (p_node), 4, operand1, res, CLEANUP) - if (operand1->type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } + CHECK_IS_INTEGER_TYPE(p_node, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) + if (!(result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + if(p_node->word_count < 5) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + goto CLEANUP; + } + p_node->num_id_operands = 1; + p_node->num_literal_words = p_node->word_count - 5; + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { - uint32_t cur_offset = 5; - SpvReflectValueData* current_data = &operand1->data; - SpvReflectTypeDescription* current_type = operand1->type; - for (; cur_offset < p_node->word_count; ++cur_offset) { - uint32_t member_index; - EVAL_CHECKED_READU32(p_eval, p_node->word_offset+cur_offset, member_index, res, CLEANUP); - res = GetMemberByIndex(p_eval->member_type_finder, current_data, current_type, member_index, ¤t_data, ¤t_type); - if (res != SPV_REFLECT_RESULT_SUCCESS) { - goto CLEANUP; - } - } - if (current_type->id != result->type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - res = CopyValueData(current_type, &result->data, current_data); - if (res != SPV_REFLECT_RESULT_SUCCESS) { - goto CLEANUP; + GET_OPERAND(p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) + if (p_node->id_operands[0]->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + + SpvReflectValueData* current_data = &p_node->id_operands[0]->value.data; + SpvReflectTypeDescription* current_type = p_node->id_operands[0]->value.type; + for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { + uint32_t member_index; + EVAL_CHECKED_READU32(p_eval, p_node->word_offset + 5 + i, member_index, res, CLEANUP); + p_node->literal_words[i] = member_index; + res = GetMemberByIndex(p_eval->member_type_finder, current_data, current_type, member_index, ¤t_data, ¤t_type); + if (res != SPV_REFLECT_RESULT_SUCCESS) { + goto CLEANUP; + } + } + if (current_type->id != p_node->value.type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + } + break; } } break; case SpvOpCompositeInsert: { + switch (evaluation_mode) { + default: + { + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + } + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + EVALUATE_OPERAND(p_node->id_operands[0],res,CLEANUP) + res = CopyValueData(p_node->value.type, &p_node->value.data, &p_node->id_operands[0]->value.data); + if (res != SPV_REFLECT_RESULT_SUCCESS) { + goto CLEANUP; + } + SpvReflectValueData* current_data = &result->data; + SpvReflectTypeDescription* current_type = result->type; + for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { + uint32_t member_index; + EVAL_CHECKED_READU32(p_eval, p_node->word_offset + 6 + i, member_index, res, CLEANUP); + p_node->literal_words[i] = member_index; + res = GetMemberByIndex(p_eval->member_type_finder, current_data, current_type, member_index, ¤t_data, ¤t_type); + if (res != SPV_REFLECT_RESULT_SUCCESS) { + goto CLEANUP; + } + } + if (current_type->id != p_node->id_operands[0]->value.type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + EVALUATE_OPERAND(p_node->id_operands[1], res, CLEANUP) + res = CopyValueData(current_type, current_data, &p_node->id_operands[1]->value.data); + if (res != SPV_REFLECT_RESULT_SUCCESS) { + goto CLEANUP; + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + if (p_node->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } - if (result->type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } + CHECK_IS_INTEGER_TYPE(p_node, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) + if (!(result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } - SpvReflectValue* operand2 = NULL; - GET_OPERAND((p_eval), (p_node), 5, operand2, res, CLEANUP) - if (operand2->type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - if (operand2->type) { - if (operand2->type->id != result->type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - } - else { - if (result->type->type_flags != SPV_REFLECT_TYPE_FLAG_BOOL) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - } - result->data = operand2->data; - - SpvReflectValue* operand1 = NULL; - GET_OPERAND((p_eval), (p_node), 4, operand1, res, CLEANUP) - - uint32_t cur_offset = 6; - SpvReflectValueData* current_data = &result->data; - SpvReflectTypeDescription* current_type = result->type; - for (; cur_offset < p_node->word_count; ++cur_offset) { - uint32_t member_index; - EVAL_CHECKED_READU32(p_eval, p_node->word_offset + cur_offset, member_index, res, CLEANUP); - res = GetMemberByIndex(p_eval->member_type_finder, current_data, current_type, member_index, ¤t_data, ¤t_type); - if (res != SPV_REFLECT_RESULT_SUCCESS) { - goto CLEANUP; - } - } + if (p_node->word_count < 6) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + goto CLEANUP; + } + p_node->num_id_operands = 2; + p_node->num_literal_words = p_node->word_count - 6; + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { + // the value to modify to + GET_OPERAND(p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) + if (p_node->id_operands[0]->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } - if (current_type->id != operand1->type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } + // the original value + GET_OPERAND(p_eval, p_node, 5, p_node->id_operands[1], res, CLEANUP) + if (p_node->id_operands[1]->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } - res = CopyValueData(current_type, current_data, &operand1->data); - if (res != SPV_REFLECT_RESULT_SUCCESS) { - goto CLEANUP; + if (p_node->id_operands[1]->value.type->id != p_node->value.type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + + SpvReflectValueData* current_data = &result->data; + SpvReflectTypeDescription* current_type = result->type; + for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { + uint32_t member_index; + EVAL_CHECKED_READU32(p_eval, p_node->word_offset + 6 + i, member_index, res, CLEANUP); + p_node->literal_words[i] = member_index; + res = GetMemberByIndex(p_eval->member_type_finder, current_data, current_type, member_index, ¤t_data, ¤t_type); + if (res != SPV_REFLECT_RESULT_SUCCESS) { + goto CLEANUP; + } + } + if (current_type->id != p_node->id_operands[0]->value.type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + } + break; } } break; case SpvOpLogicalOr: - DO_BINARY_BOOLEAN_LOGICAL_OPERATION(result, p_eval, p_node, ||, res, CLEANUP) + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(p_eval, p_node, ||, res, CLEANUP) break; case SpvOpLogicalAnd: - DO_BINARY_BOOLEAN_LOGICAL_OPERATION(result, p_eval, p_node, && , res, CLEANUP) + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(p_eval, p_node, && , res, CLEANUP) break; case SpvOpLogicalNot: { - CHECK_INSTRUCTION_SIZE(p_node, 5) - - /* check result type */ - CHECK_IS_BOOLEAN_TYPE(result, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(result, res, CLEANUP) - - /* get operand */ - SpvReflectValue* operand1 = NULL; - GET_OPERAND((p_eval), (p_node), 4, operand1, res, CLEANUP) - CHECK_IS_BOOLEAN_TYPE(operand1, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) - - /* vectors must be of same size */ - uint32_t vec_size = 1; - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, result, operand1, res, CLEANUP) - - for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1->data.numeric.vector.value[i].undefined_value) { - result->data.numeric.vector.value[i].undefined_value = 1; - } - /* write to correct offset */ - result->data.numeric.vector.value[i].value.uint32_bool_value = !operand1->data.numeric.vector.value[i].value.uint32_bool_value; + switch (evaluation_mode) { + default: + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + uint32_t vec_size = 1; + if (p_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + vec_size = p_node->value.type->traits.numeric.vector.component_count; + } + SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; + EVALUATE_OPERAND(operand1, res, CLEANUP) + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1->value.data.numeric.vector.value[i].undefined_value) { + result->data.numeric.vector.value[i].undefined_value = 1; + } + result->data.numeric.vector.value[i].value.uint32_bool_value = !operand1->value.data.numeric.vector.value[i].value.uint32_bool_value; + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + CHECK_INSTRUCTION_SIZE(p_node, 5) + p_node->num_id_operands = 1; + p_node->num_literal_words = 0; + + /* check result type */ + CHECK_IS_BOOLEAN_TYPE(p_node, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) + if (p_node->value.type->traits.numeric.scalar.signedness) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { + GET_OPERAND(p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) + CHECK_IS_BOOLEAN_TYPE(p_node->id_operands[0], res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) + + uint32_t vec_size = 1; + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_node, p_node->id_operands[0], res, CLEANUP) + } + break; } } break; - case SpvOpLogicalEqual: - DO_BINARY_BOOLEAN_LOGICAL_OPERATION(result, p_eval, p_node, ==, res, CLEANUP) + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(p_eval, p_node, ==, res, CLEANUP) break; case SpvOpLogicalNotEqual: - DO_BINARY_BOOLEAN_LOGICAL_OPERATION(result, p_eval, p_node, != , res, CLEANUP) + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(p_eval, p_node, != , res, CLEANUP) break; case SpvOpSelect: // same as c/cpp code: a ? b : c; // should allow composite types if not for spec-constant since 1.4 { - CHECK_INSTRUCTION_SIZE((p_node), 7) - /* check result type, different from other instance since - it should support composite type if not for spec constant */ - if (result->type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - - SpvReflectValue* operand1 = NULL; - GET_OPERAND((p_eval), (p_node), 4, operand1, res, CLEANUP) - CHECK_IS_BOOLEAN_TYPE(operand1, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(operand1, res, CLEANUP) - - uint32_t vec_size = 1; - // result can be vector if operand is scalar. - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, operand1, result, res, CLEANUP); - - - SpvReflectValue* operand2 = NULL; - if (p_eval->flags & SPIRV_REFLECT_EVALUATION_FLAG_ALL_BRANCH) { - GET_OPERAND((p_eval), (p_node), 5, operand2, res, CLEANUP) - if (operand2->type->id != result->type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - } - SpvReflectValue* operand3 = NULL; - if (p_eval->flags & SPIRV_REFLECT_EVALUATION_FLAG_ALL_BRANCH) { - GET_OPERAND((p_eval), (p_node), 6, operand3, res, CLEANUP) - if (operand3->type->id != result->type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - } - - if (vec_size != 1) { - if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + switch (evaluation_mode) { + default: + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; goto CLEANUP; - } - - for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1->data.numeric.vector.value[i].undefined_value) { - result->data.numeric.vector.value[i].undefined_value = 1; - } - if (operand1->data.numeric.vector.value[i].value.uint32_bool_value) { - if(!operand2) { - GET_OPERAND((p_eval), (p_node), 5, operand2, res, CLEANUP) - if (operand2->type->id != result->type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; + SpvReflectPrvEvaluationNode* operand2 = p_node->id_operands[1]; + SpvReflectPrvEvaluationNode* operand3 = p_node->id_operands[2]; + EVALUATE_OPERAND(operand1, res, CLEANUP); + if(operand1->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR){ + uint32_t vec_size = operand1->value.type->traits.numeric.vector.component_count; + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1->value.data.numeric.vector.value[i].undefined_value) { + result->data.numeric.vector.value[i].undefined_value = 1; + } + if (operand1->value.data.numeric.vector.value[i].value.uint32_bool_value) { + EVALUATE_OPERAND(operand2, res, CLEANUP) + if (operand2->value.data.numeric.vector.value[i].undefined_value) { + result->data.numeric.vector.value[i].undefined_value = 1; + } + result->data.numeric.vector.value[i].value = operand2->value.data.numeric.vector.value[i].value; + } + else { + EVALUATE_OPERAND(operand3, res, CLEANUP) + if (operand3->value.data.numeric.vector.value[i].undefined_value) { + result->data.numeric.vector.value[i].undefined_value = 1; + } + result->data.numeric.vector.value[i].value = operand3->value.data.numeric.vector.value[i].value; + } } } - if (operand2->data.numeric.vector.value[i].undefined_value) { - result->data.numeric.vector.value[i].undefined_value = 1; - } - result->data.numeric.vector.value[i].value = operand2->data.numeric.vector.value[i].value; - } - else { - if(!operand3){ - GET_OPERAND((p_eval), (p_node), 6, operand3, res, CLEANUP) - if (operand3->type->id != result->type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; + else { + if(operand1->value.data.numeric.scalar.value.uint32_bool_value) { + EVALUATE_OPERAND(operand2, res, CLEANUP) + result->data = operand2->value.data; + } + else { + EVALUATE_OPERAND(operand3, res, CLEANUP) + result->data = operand3->value.data; + } + if (operand1->value.data.numeric.scalar.undefined_value) { + // we shouldn't care about content here... + for (uint32_t i = 0; i < SPV_REFLECT_MAX_VECTOR_DIMS; ++i) { + result->data.numeric.vector.value[i].undefined_value = 1; + } } } - if (operand3->data.numeric.vector.value[i].undefined_value) { - result->data.numeric.vector.value[i].undefined_value = 1; - } - result->data.numeric.vector.value[i].value = operand3->data.numeric.vector.value[i].value; } - } - } - else { - // deep copy value, inherit undefined value - - // we can't deal with other types for now... - if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; - goto CLEANUP; - } - - if (operand1->data.numeric.scalar.value.uint32_bool_value) { - if(!operand2) { - GET_OPERAND((p_eval), (p_node), 5, operand2, res, CLEANUP) - if (operand2->type->id != result->type->id) { + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + CHECK_INSTRUCTION_SIZE((p_node), 7) + p_node->num_id_operands = 3; + p_node->num_literal_words = 0; + + // check result type + if (p_node->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; } } - // need deep copy if complex - *result = *operand2; - } - else { - if(!operand3) { - GET_OPERAND((p_eval), (p_node), 6, operand3, res, CLEANUP) - if (operand3->type->id != result->type->id) { + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { + GET_OPERAND(p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) + CHECK_IS_BOOLEAN_TYPE(p_node->id_operands[0], res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) + + GET_OPERAND(p_eval, p_node, 5, p_node->id_operands[1], res, CLEANUP) + if (p_node->id_operands[1]->value.type->id != p_node->value.type->id) { res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; } + + GET_OPERAND(p_eval, p_node, 6, p_node->id_operands[2], res, CLEANUP) + if (p_node->id_operands[2]->value.type->id != p_node->value.type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + + if (p_node->id_operands[0]->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + // spec says only about "component" selection, but we only deal with vector for now... + if(p_node->value.type->type_flags & VECTOR_DISALLOWED_FLAGS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + goto CLEANUP; + } + if(p_node->value.type->traits.numeric.vector.component_count != p_node->id_operands[0]->value.type->traits.numeric.vector.component_count) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + } + else { + // no checking is needed for now... + } } - // need deep copy if complex - *result = *operand3; - } - if (operand1->data.numeric.scalar.undefined_value) { - // we shouldn't care about content here... - for (uint32_t i = 0; i < SPV_REFLECT_MAX_VECTOR_DIMS; ++i) { - result->data.numeric.vector.value[i].undefined_value = 1; - } - } + break; } } break; case SpvOpIEqual: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, ==, res, CLEANUP) + DO_BINARY_UINTEGER_LOGICAL_OPERATION(p_eval, p_node, ==, res, CLEANUP) break; case SpvOpINotEqual: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, != , res, CLEANUP) + DO_BINARY_UINTEGER_LOGICAL_OPERATION(p_eval, p_node, != , res, CLEANUP) break; case SpvOpULessThan: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, < , res, CLEANUP) + DO_BINARY_UINTEGER_LOGICAL_OPERATION(p_eval, p_node, < , res, CLEANUP) break; case SpvOpSLessThan: - DO_BINARY_SINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, < , res, CLEANUP) + DO_BINARY_SINTEGER_LOGICAL_OPERATION(p_eval, p_node, < , res, CLEANUP) break; case SpvOpUGreaterThan: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, > , res, CLEANUP) + DO_BINARY_UINTEGER_LOGICAL_OPERATION(p_eval, p_node, > , res, CLEANUP) break; case SpvOpSGreaterThan: - DO_BINARY_SINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, > , res, CLEANUP) + DO_BINARY_SINTEGER_LOGICAL_OPERATION(p_eval, p_node, > , res, CLEANUP) break; case SpvOpULessThanEqual: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, <= , res, CLEANUP) + DO_BINARY_UINTEGER_LOGICAL_OPERATION(p_eval, p_node, <= , res, CLEANUP) break; case SpvOpSLessThanEqual: - DO_BINARY_SINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, <= , res, CLEANUP) + DO_BINARY_SINTEGER_LOGICAL_OPERATION(p_eval, p_node, <= , res, CLEANUP) break; case SpvOpUGreaterThanEqual: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, >= , res, CLEANUP) + DO_BINARY_UINTEGER_LOGICAL_OPERATION(p_eval, p_node, >= , res, CLEANUP) break; case SpvOpSGreaterThanEqual: - DO_BINARY_SINTEGER_LOGICAL_OPERATION(result, p_eval, p_node, >= , res, CLEANUP) + DO_BINARY_SINTEGER_LOGICAL_OPERATION(p_eval, p_node, >= , res, CLEANUP) break; // check shader capability... vulkan should assume this... @@ -6921,21 +7338,56 @@ SpvReflectResult EvaluateResultImpl(SpvReflectEvaluation* p_eval, uint32_t resul break; } CLEANUP: - if (res != SPV_REFLECT_RESULT_SUCCESS) { - p_node->evaluation_state = SPV_REFLECT_EVALUATION_STATE_FAILED; - } - else { - p_node->evaluation_state = SPV_REFLECT_EVALUATION_STATE_DONE; + switch(evaluation_mode) { + default: + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED; + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + if (res != SPV_REFLECT_RESULT_SUCCESS) { + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_FAILED; + } + else { + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_DONE; + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + if (res != SPV_REFLECT_RESULT_SUCCESS) { + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED; + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + if (res != SPV_REFLECT_RESULT_SUCCESS) { + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED; + } + else { + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_PENDING; + } + break; } + return res; } SpvReflectEvaluation* spvReflectGetEvaluationInterface(SpvReflectShaderModule* p_module) { + // build ast here. return p_module->_internal->evaluator; } +bool HaveNodeInTree(const SpvReflectPrvEvaluationNode* p_node_root, const SpvReflectPrvEvaluationNode* p_node_expected) +{ + if (p_node_root == p_node_expected) { + return true; + } + for (uint32_t i = 0; i < p_node_root->num_id_operands; ++i) { + if (HaveNodeInTree(p_node_root->id_operands[i], p_node_expected)) { + return true; + } + } + return false; +} + SpvReflectResult spvReflectSetSpecConstantValue(SpvReflectEvaluation* p_eval, uint32_t specId, SpvReflectScalarType type, const SpvReflectScalarValueData* value) { SpvReflectPrvEvaluationNode* p_node = FindSpecIdNode(p_eval, specId); @@ -6980,18 +7432,11 @@ SpvReflectResult spvReflectSetSpecConstantValue(SpvReflectEvaluation* p_eval, ui break; } p_node->value.data.numeric.scalar = *value; - p_node->evaluation_state = SPV_REFLECT_EVALUATION_STATE_UPDATED; + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED; // update state tracking here... for (uint32_t i = 0; i < p_eval->node_count; ++i) { - bool exist_in_op = false; - for (uint32_t j = 0; j < p_eval->nodes[i].related_id_count; ++j) { - if (p_eval->nodes[i].related_specId[j] == specId) { - exist_in_op = true; - break; - } - } - if (exist_in_op) { - p_eval->nodes[i].evaluation_state = SPV_REFLECT_EVALUATION_STATE_UPDATED; + if (HaveNodeInTree(&p_eval->nodes[i], p_node)) { + p_eval->nodes[i].evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED; } } return SPV_REFLECT_RESULT_SUCCESS; @@ -7012,19 +7457,23 @@ SpvReflectResult spvReflectEvaluateResult(SpvReflectEvaluation* p_eval, uint32_t if (!result || !p_eval) { return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; } - return EvaluateResultImpl(p_eval, result_id, result); + SpvReflectPrvEvaluationNode* p_node = FindEvaluationNode(p_eval, result_id); + SpvReflectResult res = EvaluateResult_Do(p_node); + *result = &p_node->value; + return res; } int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id, uint32_t specId) { SpvReflectPrvEvaluationNode* p_node = FindEvaluationNode(p_eval, result_id); if (!p_node) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; + return 0; } - for (uint32_t i = 0; i < p_node->related_id_count; ++i) { - if (p_node->related_specId[i] == specId) return 1; + SpvReflectPrvEvaluationNode* p_spec = FindSpecIdNode(p_eval, specId); + if (!p_node) { + return 0; } - return 0; + return HaveNodeInTree(p_node, p_spec); } diff --git a/spirv_reflect.h b/spirv_reflect.h index 96320ba7..1e54ad59 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -1604,7 +1604,7 @@ SpvReflectResult spvReflectEvaluateResult(SpvReflectEvaluation* p_eval, uint32_t @param result_id The result id in concern @param specId The specId in concern @param ids Readonly array of specids - @return 1 if may be related, 0 otherwise + @return 1 if may be related, 0 otherwise (may be a silent error) */ int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id, uint32_t specId); From 555b2826e48d251e5d2e31118d6504f4fae967e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sat, 6 Aug 2022 20:10:13 +0800 Subject: [PATCH 16/44] core code done Still need to format into 2 spaces indent. --- spirv_reflect.c | 1482 +++++++++++++++++++++++------------------------ spirv_reflect.h | 13 +- 2 files changed, 742 insertions(+), 753 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index 44263242..c613022c 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -236,8 +236,7 @@ typedef struct SpvReflectPrvEvaluationNode { uint32_t result_id; SpvOp op; SpvOp specOp; - uint32_t word_offset; - uint32_t word_count; + SpvReflectEvaluationNodeState evaluation_state; SpvReflectValue value; @@ -247,28 +246,38 @@ typedef struct SpvReflectPrvEvaluationNode { SpvReflectPrvEvaluationNode** id_operands; uint32_t num_literal_words; uint32_t* literal_words; + + // add another 2 passes if need explicit initialization and free... + union InstructionPrivate { + // used only in preprocess passes to replace parser FindNode + SpvReflectPrvNode* uninitialized; + struct VectorShuffle { + uint8_t idx[SPV_REFLECT_MAX_VECTOR_DIMS]; + } vector_shuffle; + struct CompositeExtract { + SpvReflectTypeDescription* src_type; + SpvReflectValueData* src_data; + } composite_extract; + struct CompositeInsert { + SpvReflectTypeDescription* dst_type; + SpvReflectValueData* dst_data; + }composite_insert; + } instruction_private; } SpvReflectPrvEvaluationNode; // clang-format on // clang-format off -typedef enum SpvReflectEvaluationState { +typedef enum SpvReflectEvaluationMode { SPIRV_REFLECT_EVALUATION_MODE_NORMAL = 0, // traverse all branches, currently for OpSelect SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS = 1, SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS = 2, -} SpvReflectEvaluationState; +} SpvReflectEvaluationMode; typedef struct SpvReflectEvaluation { - // original code if no-copy, else it's a copy of constant instructions - size_t spirv_word_count; - uint32_t* spirv_code; - uint32_t node_count; SpvReflectPrvEvaluationNode* nodes; - // To flag dry run and tree traversal... - SpvReflectEvaluationState state; - SpvReflectPrvEvaluationNode** id_operand_buffer; uint32_t* literal_word_buffer; @@ -426,7 +435,7 @@ static bool InRange( } static SpvReflectResult ReadU32( - SpvReflectPrvParser* p_parser, + const SpvReflectPrvParser* p_parser, uint32_t word_offset, uint32_t* p_value) { @@ -570,7 +579,7 @@ static void ApplyArrayTraits(const SpvReflectTypeDescription* p_type, SpvReflect } static SpvReflectPrvNode* FindNode( - SpvReflectPrvParser* p_parser, + const SpvReflectPrvParser* p_parser, uint32_t result_id) { SpvReflectPrvNode* p_node = NULL; @@ -3474,36 +3483,9 @@ static SpvReflectResult ParseExecutionModes( return SPV_REFLECT_RESULT_SUCCESS; } -static bool EvalCodeInRange( - const SpvReflectEvaluation* p_eval, - uint32_t index) -{ - bool in_range = false; - if (IsNotNull(p_eval)) { - in_range = (index < p_eval->spirv_word_count); - } - return in_range; -} - -static SpvReflectResult EvalReadU32( - const SpvReflectEvaluation* p_eval, - uint32_t word_offset, - uint32_t* p_value) -{ - assert(IsNotNull(p_eval)); - assert(IsNotNull(p_eval->spirv_code)); - assert(EvalCodeInRange(p_eval, word_offset)); - SpvReflectResult result = SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_EOF; - if (IsNotNull(p_eval) && IsNotNull(p_eval->spirv_code) && EvalCodeInRange(p_eval, word_offset)) { - *p_value = *(p_eval->spirv_code + word_offset); - result = SPV_REFLECT_RESULT_SUCCESS; - } - return result; -} - -#define EVAL_CHECKED_READU32(eval, word_offset, value, res, cleanup) \ +#define EVAL_CHECKED_READU32(parser, word_offset, value, res, cleanup) \ { \ - res = EvalReadU32(eval, \ + res = ReadU32(parser, \ word_offset, (uint32_t*)&(value)); \ if (res != SPV_REFLECT_RESULT_SUCCESS) { \ goto cleanup; \ @@ -3519,19 +3501,20 @@ static SpvReflectResult EvalReadU32( #define COMPOSITE_DISALLOWED_FLAGS (~0 ^ COMPOSITE_TYPE_FLAGS) // getting constant also happens before evaluation is created. -static SpvReflectResult EvalGetScalarConstant(const SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node) +static SpvReflectResult EvalGetScalarConstant(const SpvReflectPrvParser* p_parser, SpvReflectPrvEvaluationNode* p_node) { SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS; if(p_node->value.type->type_flags & SCALAR_DISALLOWED_FLAGS) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + SpvReflectPrvNode* p_parser_node = FindNode(p_parser, p_node->result_id); uint32_t low_word; - EVAL_CHECKED_READU32(p_eval, p_node->word_offset + 3, low_word, result, CLEANUP); + EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 3, low_word, result, CLEANUP); // There is no alignment requirements in c/cpp for unions if (p_node->value.type->traits.numeric.scalar.width == 32) { memcpy(&p_node->value.data.numeric.scalar.value.uint32_bool_value, &low_word, 4); } else if (p_node->value.type->traits.numeric.scalar.width ==64) { uint32_t high_word; - EVAL_CHECKED_READU32(p_eval, p_node->word_offset + 4, high_word, result, CLEANUP); + EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 4, high_word, result, CLEANUP); uint64_t combined = low_word | (((uint64_t)high_word) << 32); memcpy(&p_node->value.data.numeric.scalar.value.uint64_value, &combined, 8); } @@ -3584,9 +3567,33 @@ static SpvReflectResult ParserGetScalarConstant(const SpvReflectShaderModule* p_ // defined later.. static SpvReflectSpecializationConstant* GetSpecContantById(const SpvReflectShaderModule* p_module, uint32_t constant_id); -static SpvReflectResult EvaluateResult_Do(SpvReflectPrvEvaluationNode* p_node); -static SpvReflectResult EvaluateResult_1PASS(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node); -static SpvReflectResult EvaluateResult_2PASS(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node); + + +#ifdef _MSC_VER +#define SPIRV_REFLECT_FORCEINLINE __forceinline +#else +#define SPIRV_REFLECT_FORCEINLINE __attribute__((always_inline)) inline +#endif + +static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node, SpvReflectEvaluationMode evaluation_mode, SpvReflectPrvParser* p_parser); + +// only need node for evaluation.. Type information should not be freed before evaluating for now. +// may move type info into instruction info later, but now it seems not needed... +static SpvReflectResult EvaluateResult_Do(SpvReflectPrvEvaluationNode* p_node) +{ + return EvaluateResult_Impl(NULL, p_node, SPIRV_REFLECT_EVALUATION_MODE_NORMAL, NULL); +} +// 1 PASS parser needs to read specOp and check instruction size +static SpvReflectResult EvaluateResult_1PASS(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node, SpvReflectPrvParser* p_parser) +{ + return EvaluateResult_Impl(p_eval, p_node, SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS, p_parser); +} + +// 2 PASS needs parser to get id operands and literals +static SpvReflectResult EvaluateResult_2PASS(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node, SpvReflectPrvParser* p_parser) +{ + return EvaluateResult_Impl(p_eval, p_node, SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS, p_parser); +} static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) { @@ -3678,19 +3685,6 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars if(!p_eval->nodes){ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; } - if (p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT_NO_COPY) { - // use original code for evaluation. - p_eval->spirv_code = p_module->_internal->spirv_code; - p_eval->spirv_word_count = p_module->_internal->spirv_word_count; - } - else if (p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT) { - // need to copy instructions from code for later evaluation. - p_eval->spirv_code = (uint32_t*)malloc(instruction_size * sizeof(uint32_t)); - if (!p_module->_internal->evaluator->spirv_code) { - return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; - } - p_eval->spirv_word_count = instruction_size; - } // need to update correct offset in new code if not no-copy uint32_t current_offset = 0; @@ -3702,7 +3696,6 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars p_eval->nodes[current_cinst].op = p_node->op; p_eval->nodes[current_cinst].specOp = (SpvOp)INVALID_VALUE; p_eval->nodes[current_cinst].result_id = p_node->result_id; - p_eval->nodes[current_cinst].word_count = p_node->word_count; p_eval->nodes[current_cinst].value.type = FindType(p_module, p_node->result_type_id); if (!p_module->_internal->evaluator->nodes[current_cinst].value.type) { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; @@ -3719,14 +3712,8 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars p_eval->nodes[current_cinst].evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_FAILED; } } + p_eval->nodes[current_cinst].instruction_private.uninitialized = p_node; p_eval->nodes[current_cinst].specId = p_node->decorations.specialization_constant.value; - if (p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT_NO_COPY) { - p_eval->nodes[current_cinst].word_offset = p_node->word_offset; - } - else { - p_eval->nodes[current_cinst].word_offset = current_offset; - memcpy(p_module->_internal->evaluator->spirv_code + current_offset, p_module->_internal->spirv_code + p_node->word_offset, 4 * p_node->word_count); - } ++current_cinst; current_offset += p_node->word_count; } @@ -3738,7 +3725,7 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars // do not need to find what constant literals are related to if(!IS_CONSTANT_LITERAL_OP(p_ev_node->op)){ // reset evaluation state for tracking which ones are touched - EvaluateResult_1PASS(p_eval, p_ev_node); + EvaluateResult_1PASS(p_eval, p_ev_node, p_parser); } } uint32_t literal_words = 0; @@ -3747,7 +3734,6 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars SpvReflectPrvEvaluationNode* p_ev_node = &p_eval->nodes[i]; // do not need to find what constant literals are related to if (!IS_CONSTANT_LITERAL_OP(p_ev_node->op) && p_ev_node->evaluation_state == SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED) { - // reset evaluation state for tracking which ones are touched literal_words += p_ev_node->num_literal_words; id_operands += p_ev_node->num_id_operands; } @@ -3765,7 +3751,6 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars uint32_t literal_offset = 0; for (uint32_t i = 0; i < p_eval->node_count; ++i) { SpvReflectPrvEvaluationNode* p_ev_node = &p_eval->nodes[i]; - // do not need to find what constant literals are related to if (!IS_CONSTANT_LITERAL_OP(p_ev_node->op) && p_ev_node->evaluation_state == SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED) { p_ev_node->id_operands = p_eval->id_operand_buffer + id_offset; p_ev_node->literal_words = p_eval->literal_word_buffer + literal_offset; @@ -3773,13 +3758,13 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars id_offset += p_ev_node->num_id_operands; } } + SPV_REFLECT_ASSERT(id_offset == id_operands); + SPV_REFLECT_ASSERT(literal_offset == literal_words); // 2 PASS for (uint32_t i = 0; i < p_eval->node_count; ++i) { SpvReflectPrvEvaluationNode* p_ev_node = &p_eval->nodes[i]; - // do not need to find what constant literals are related to if(!IS_CONSTANT_LITERAL_OP(p_ev_node->op)){ - // reset evaluation state for tracking which ones are touched - EvaluateResult_2PASS(p_eval, p_ev_node); + EvaluateResult_2PASS(p_eval, p_ev_node, p_parser); } } } @@ -3788,12 +3773,10 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars return SPV_REFLECT_RESULT_SUCCESS; } -static void DestroyEvaluator(SpvReflectEvaluation* evaluator, bool owns_code) +static void DestroyEvaluator(SpvReflectEvaluation* evaluator) { SafeFree(evaluator->nodes); - if (owns_code) { - SafeFree(evaluator->spirv_code); - } + SafeFree(evaluator->id_operand_buffer); SafeFree(evaluator->literal_word_buffer); } @@ -4374,7 +4357,7 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module) } if (p_module->_internal->module_flags & MODULE_EVALUATION_FLAGS) { - DestroyEvaluator(p_module->_internal->evaluator, !(p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT_NO_COPY)); + DestroyEvaluator(p_module->_internal->evaluator); SafeFree(p_module->_internal->evaluator) } @@ -5623,55 +5606,55 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect } \ } -#define CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_result_node, p_op1_node, res, CLEANUP) \ -{ \ - if ((p_result_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ - if (!((p_op1_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - if ((p_op1_node)->value.type->traits.numeric.vector.component_count != (p_result_node)->value.type->traits.numeric.vector.component_count) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - vec_size = (p_result_node)->value.type->traits.numeric.vector.component_count; \ - } \ -} - -#define CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, p_result_node, p_op1_node, p_op2_node, res, CLEANUP)\ -{ \ - if ((p_result_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ - if (!((p_op1_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - if (!((p_op2_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - if ((p_op1_node)->value.type->traits.numeric.vector.component_count != (p_result_node)->value.type->traits.numeric.vector.component_count) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - if ((p_op2_node)->value.type->traits.numeric.vector.component_count != (p_result_node)->value.type->traits.numeric.vector.component_count) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - vec_size = (p_result_node)->value.type->traits.numeric.vector.component_count; \ - } \ -} - -#define CHECK_WIDTH_MATCH(p_node1, p_node2, res, CLEANUP) \ -{ \ - if ((p_node1)->value.type->traits.numeric.scalar.width != (p_node2)->value.type->traits.numeric.scalar.width) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ -} - -#define CHECK_IS_BASIC_TYPE(p_result_node, b_type, res, CLEANUP) \ +#define CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_result_node, p_op1_node, res, CLEANUP) \ +{ \ + if ((p_result_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + if (!((p_op1_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + if ((p_op1_node)->value.type->traits.numeric.vector.component_count != (p_result_node)->value.type->traits.numeric.vector.component_count) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + vec_size = (p_result_node)->value.type->traits.numeric.vector.component_count; \ + } \ +} + +#define CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, p_result_node, p_op1_node, p_op2_node, res, CLEANUP) \ +{ \ + if ((p_result_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + if (!((p_op1_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + if (!((p_op2_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + if ((p_op1_node)->value.type->traits.numeric.vector.component_count != (p_result_node)->value.type->traits.numeric.vector.component_count) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + if ((p_op2_node)->value.type->traits.numeric.vector.component_count != (p_result_node)->value.type->traits.numeric.vector.component_count) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + vec_size = (p_result_node)->value.type->traits.numeric.vector.component_count; \ + } \ +} + +#define CHECK_WIDTH_MATCH(p_node1, p_node2, res, CLEANUP) \ +{ \ + if ((p_node1)->value.type->traits.numeric.scalar.width != (p_node2)->value.type->traits.numeric.scalar.width) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ +} + +#define CHECK_IS_BASIC_TYPE(p_result_node, b_type, res, CLEANUP) \ { \ - if(((p_result_node)->value.type->type_flags & SCALAR_TYPE_FLAGS) != b_type) { \ + if(((p_result_node)->value.type->type_flags & SCALAR_TYPE_FLAGS) != b_type) { \ res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ goto CLEANUP; \ } \ @@ -5682,268 +5665,272 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect #define CHECK_IS_BOOLEAN_TYPE(p_result_node, res, CLEANUP) CHECK_IS_BASIC_TYPE(p_result_node, SPV_REFLECT_TYPE_FLAG_BOOL, res, CLEANUP) -#define CHECK_VECTOR_OR_SCALAR_TYPE(p_result_node, res, CLEANUP) \ -{ \ - if ((p_result_node)->value.type && ((p_result_node)->value.type->type_flags & VECTOR_DISALLOWED_FLAGS)) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ -} \ +#define CHECK_VECTOR_OR_SCALAR_TYPE(p_result_node, res, CLEANUP) \ +{ \ + if ((p_result_node)->value.type && ((p_result_node)->value.type->type_flags & VECTOR_DISALLOWED_FLAGS)) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ +} -#define GET_OPERAND(eval, p_node, offset, p_result_node, res, CLEANUP) \ -{ \ - uint32_t operand_id; \ - EVAL_CHECKED_READU32(eval, p_node->word_offset + offset, operand_id, res, CLEANUP); \ - p_result_node = FindEvaluationNode(p_eval, operand_id); \ - if(!p_result_node) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; \ - goto CLEANUP; \ - } \ +#define GET_OPERAND(p_parser, eval, p_node, offset, p_result_node, res, CLEANUP) \ +{ \ + uint32_t operand_id; \ + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; \ + EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + offset, operand_id, res, CLEANUP); \ + p_result_node = FindEvaluationNode(p_eval, operand_id); \ + if(!p_result_node) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; \ + goto CLEANUP; \ + } \ } -#define EVALUATE_OPERAND(p_result_node, res, CLEANUP) \ -{ \ - res = EvaluateResult_Do(p_result_node); \ - if (res != SPV_REFLECT_RESULT_SUCCESS) goto CLEANUP;\ +#define EVALUATE_OPERAND(p_result_node, res, CLEANUP) \ +{ \ + res = EvaluateResult_Do(p_result_node); \ + if (res != SPV_REFLECT_RESULT_SUCCESS) goto CLEANUP; \ } #define SIMPLE_UNARY_OP_32_BIT_HOOK #define SIMPLE_UNARY_OP_64_BIT_HOOK -#define DO_SIMPLE_UNARY_INTEGER_OPERATION(simple_op_eval, p_node, res, CLEANUP) \ -{ \ - switch (evaluation_mode) { \ - default: \ - {\ - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR;\ - goto CLEANUP;\ - }\ - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL:\ - {\ - uint32_t vec_size = 1;\ - if (p_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) {\ - vec_size = p_node->value.type->traits.numeric.vector.component_count;\ - }\ - SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0];\ - EVALUATE_OPERAND(operand1, res, CLEANUP)\ - \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - p_node->value.data.numeric.vector.value[i].undefined_value \ - = operand1->value.data.numeric.vector.value[i].undefined_value; \ - switch (operand1->value.type->traits.numeric.scalar.width) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - case 32: \ - /* 32 bit integer */ \ - { \ - int32_t data = operand1->value.data.numeric.vector.value[i].value.sint32_value; \ - SIMPLE_UNARY_OP_32_BIT_HOOK \ - p_node->value.data.numeric.vector.value[i].value.sint32_value = data; \ - } \ - break; \ - case 64: \ - /* 64 bit integer */ \ - { \ - int64_t data = operand1->value.data.numeric.vector.value[i].value.sint64_value; \ - SIMPLE_UNARY_OP_64_BIT_HOOK \ - p_node->value.data.numeric.vector.value[i].value.sint64_value = data; \ - } \ - break; \ - } \ - } \ - } \ - break;\ - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS:\ - {\ - CHECK_INSTRUCTION_SIZE(p_node, 5)\ - p_node->num_id_operands = 1;\ - p_node->num_literal_words = 0;\ - \ - /* check result type */\ - CHECK_IS_INTEGER_TYPE(p_node, res, CLEANUP)\ - CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP)\ - }\ - break;\ - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS:\ - {\ - GET_OPERAND((simple_op_eval), p_node, 4, p_node->id_operands[0], res, CLEANUP)\ - CHECK_IS_INTEGER_TYPE(p_node->id_operands[0], res, CLEANUP)\ - CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP)\ - CHECK_WIDTH_MATCH(p_node, p_node->id_operands[0], res, CLEANUP)\ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_node, p_node->id_operands[0], res, CLEANUP)\ - }\ - break;\ - }\ +#define DO_SIMPLE_UNARY_INTEGER_OPERATION(mode, p_simple_op_parser, simple_op_eval, simple_op_node, res, CLEANUP) \ +{ \ + switch (mode) { \ + default: \ + { \ + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; \ + goto CLEANUP; \ + } \ + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: \ + { \ + uint32_t vec_size = 1; \ + if ((simple_op_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + vec_size = (simple_op_node)->value.type->traits.numeric.vector.component_count; \ + } \ + SpvReflectPrvEvaluationNode* operand1 = (simple_op_node)->id_operands[0]; \ + EVALUATE_OPERAND(operand1, res, CLEANUP) \ + \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value \ + = operand1->value.data.numeric.vector.value[i].undefined_value; \ + switch (operand1->value.type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + /* 32 bit integer */ \ + { \ + int32_t data = operand1->value.data.numeric.vector.value[i].value.sint32_value; \ + SIMPLE_UNARY_OP_32_BIT_HOOK \ + (simple_op_node)->value.data.numeric.vector.value[i].value.sint32_value = data; \ + } \ + break; \ + case 64: \ + /* 64 bit integer */ \ + { \ + int64_t data = operand1->value.data.numeric.vector.value[i].value.sint64_value; \ + SIMPLE_UNARY_OP_64_BIT_HOOK \ + (simple_op_node)->value.data.numeric.vector.value[i].value.sint64_value = data; \ + } \ + break; \ + } \ + } \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: \ + { \ + SpvReflectPrvNode* p_parser_node = simple_op_node->instruction_private.uninitialized; \ + CHECK_INSTRUCTION_SIZE(p_parser_node, 5) \ + (simple_op_node)->num_id_operands = 1; \ + (simple_op_node)->num_literal_words = 0; \ + \ + /* check result type */ \ + CHECK_IS_INTEGER_TYPE((simple_op_node), res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node), res, CLEANUP) \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: \ + { \ + GET_OPERAND((p_simple_op_parser), (simple_op_eval), (simple_op_node), 4, (simple_op_node)->id_operands[0], res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE((simple_op_node)->id_operands[0], res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node)->id_operands[0], res, CLEANUP) \ + CHECK_WIDTH_MATCH((simple_op_node), (simple_op_node)->id_operands[0], res, CLEANUP) \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, (simple_op_node), (simple_op_node)->id_operands[0], res, CLEANUP) \ + } \ + break; \ + } \ } #define SIMPLE_BINARY_OP_32_BIT_HOOK #define SIMPLE_BINARY_OP_64_BIT_HOOK -#define DO_SIMPLE_BINARY_INTEGER_OPERATION(simple_op_eval, simple_op_node, operation, res, CLEANUP) \ -{ \ - switch (evaluation_mode) { \ - default: \ - {\ - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR;\ - goto CLEANUP;\ - }\ - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL:\ - {\ - uint32_t vec_size = 1;\ - if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) {\ - vec_size = simple_op_node->value.type->traits.numeric.vector.component_count;\ - }\ - SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0];\ - SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1];\ - EVALUATE_OPERAND(operand1, res, CLEANUP)\ - EVALUATE_OPERAND(operand2, res, CLEANUP)\ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1->value.data.numeric.vector.value[i].undefined_value \ - || operand2->value.data.numeric.vector.value[i].undefined_value) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - switch ((simple_op_node)->value.type->traits.numeric.scalar.width) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - case 32: \ - { \ - /* load data into int32_t*/ \ - int32_t data1 = operand1->value.data.numeric.vector.value[i].value.sint32_value; \ - int32_t data2 = operand2->value.data.numeric.vector.value[i].value.sint32_value; \ - int32_t data = data1 operation data2; \ - SIMPLE_BINARY_OP_32_BIT_HOOK \ - /* write to correct offset */ \ - (simple_op_node)->value.data.numeric.vector.value[i].value.sint32_value = data; \ - } \ - break; \ - case 64: \ - { \ - /* load data into int64_t*/ \ - int64_t data1 = operand1->value.data.numeric.vector.value[i].value.sint64_value; \ - int64_t data2 = operand2->value.data.numeric.vector.value[i].value.sint64_value; \ - int64_t data = data1 operation data2; \ - SIMPLE_BINARY_OP_32_BIT_HOOK \ - /* write to correct offset */ \ - (simple_op_node)->value.data.numeric.vector.value[i].value.sint64_value = data; \ - } \ - break; \ - } \ - }\ - }\ - break;\ - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS:\ - {\ - CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ - simple_op_node->num_id_operands = 2;\ - simple_op_node->num_literal_words = 0;\ - \ - /* check result type */\ - CHECK_IS_INTEGER_TYPE(simple_op_node, res, CLEANUP)\ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node, res, CLEANUP)\ - }\ - break;\ - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS:\ - {\ - GET_OPERAND((simple_op_eval), simple_op_node, 4, p_node->id_operands[0], res, CLEANUP)\ - CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[0], res, CLEANUP)\ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP)\ - GET_OPERAND((simple_op_eval), p_node, 5, p_node->id_operands[1], res, CLEANUP)\ - CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[1], res, CLEANUP)\ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP)\ - \ - /* check agains result */\ - CHECK_WIDTH_MATCH(simple_op_node, p_node->id_operands[0], res, CLEANUP)\ - CHECK_WIDTH_MATCH(simple_op_node, p_node->id_operands[1], res, CLEANUP)\ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP)\ - }\ - break;\ - }\ -} - -#define DO_UNSIGNED_INTEGER_DIVISION(simple_op_eval, simple_op_node, operation, res, CLEANUP) \ -{ \ - switch (evaluation_mode) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR;\ - goto CLEANUP;\ - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL:\ - {\ - uint32_t vec_size = 1;\ - if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) {\ - vec_size = simple_op_node->value.type->traits.numeric.vector.component_count;\ - }\ - SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0];\ - SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1];\ - EVALUATE_OPERAND(operand1, res, CLEANUP)\ - EVALUATE_OPERAND(operand2, res, CLEANUP)\ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1->value.data.numeric.vector.value[i].undefined_value \ - || operand2->value.data.numeric.vector.value[i].undefined_value) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - switch ((simple_op_node)->value.type->traits.numeric.scalar.width) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - case 32: \ - { \ - (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value \ - operation operand2->value.data.numeric.vector.value[i].value.uint32_bool_value; \ - if (operand2->value.data.numeric.vector.value[i].value.uint32_bool_value == 0) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - } \ - break; \ - case 64: \ - { \ - (simple_op_node)->value.data.numeric.vector.value[i].value.uint64_value \ - = operand1->value.data.numeric.vector.value[i].value.uint64_value \ - operation operand2->value.data.numeric.vector.value[i].value.uint64_value; \ - if (operand2->value.data.numeric.vector.value[i].value.uint64_value == 0) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - } \ - break; \ - } \ - } \ - }\ - break; \ - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS:\ - {\ - CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ - simple_op_node->num_id_operands = 2;\ - simple_op_node->num_literal_words = 0;\ - \ - /* check result type */\ - CHECK_IS_INTEGER_TYPE(simple_op_node, res, CLEANUP)\ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node, res, CLEANUP)\ - if ((simple_op_node)->value.type->traits.numeric.scalar.signedness) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - }\ - break;\ - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS:\ - {\ - GET_OPERAND((simple_op_eval), simple_op_node, 4, simple_op_node->id_operands[0], res, CLEANUP)\ - if(p_node->id_operands[0]->value.type->id != p_node->value.type->id) {\ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE;\ - goto CLEANUP;\ - }\ - GET_OPERAND((simple_op_eval), simple_op_node, 5, simple_op_node->id_operands[1], res, CLEANUP)\ - if(p_node->id_operands[1]->value.type->id != p_node->value.type->id) {\ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE;\ - goto CLEANUP;\ - }\ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP)\ - }\ - break;\ - }\ +#define DO_SIMPLE_BINARY_INTEGER_OPERATION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP) \ +{ \ + switch (mode) { \ + default: \ + { \ + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; \ + goto CLEANUP; \ + } \ + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: \ + { \ + uint32_t vec_size = 1; \ + if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + vec_size = simple_op_node->value.type->traits.numeric.vector.component_count; \ + } \ + SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0]; \ + SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1]; \ + EVALUATE_OPERAND(operand1, res, CLEANUP) \ + EVALUATE_OPERAND(operand2, res, CLEANUP) \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->value.data.numeric.vector.value[i].undefined_value \ + || operand2->value.data.numeric.vector.value[i].undefined_value) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + switch ((simple_op_node)->value.type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + { \ + /* load data into int32_t*/ \ + int32_t data1 = operand1->value.data.numeric.vector.value[i].value.sint32_value; \ + int32_t data2 = operand2->value.data.numeric.vector.value[i].value.sint32_value; \ + int32_t data = data1 operation data2; \ + SIMPLE_BINARY_OP_32_BIT_HOOK \ + /* write to correct offset */ \ + (simple_op_node)->value.data.numeric.vector.value[i].value.sint32_value = data; \ + } \ + break; \ + case 64: \ + { \ + /* load data into int64_t*/ \ + int64_t data1 = operand1->value.data.numeric.vector.value[i].value.sint64_value; \ + int64_t data2 = operand2->value.data.numeric.vector.value[i].value.sint64_value; \ + int64_t data = data1 operation data2; \ + SIMPLE_BINARY_OP_32_BIT_HOOK \ + /* write to correct offset */ \ + (simple_op_node)->value.data.numeric.vector.value[i].value.sint64_value = data; \ + } \ + break; \ + } \ + } \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: \ + { \ + SpvReflectPrvNode* p_parser_node = simple_op_node->instruction_private.uninitialized; \ + CHECK_INSTRUCTION_SIZE(p_parser_node, 6) \ + simple_op_node->num_id_operands = 2; \ + simple_op_node->num_literal_words = 0; \ + \ + /* check result type */ \ + CHECK_IS_INTEGER_TYPE(simple_op_node, res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node, res, CLEANUP) \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: \ + { \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), simple_op_node, 4, (simple_op_node)->id_operands[0], res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), (simple_op_node), 5, (simple_op_node)->id_operands[1], res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ + \ + /* check agains result */ \ + CHECK_WIDTH_MATCH(simple_op_node, (simple_op_node)->id_operands[0], res, CLEANUP) \ + CHECK_WIDTH_MATCH(simple_op_node, (simple_op_node)->id_operands[1], res, CLEANUP) \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ + } \ + break; \ + } \ +} + +#define DO_UNSIGNED_INTEGER_DIVISION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP) \ +{ \ + switch (mode) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; \ + goto CLEANUP; \ + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: \ + { \ + uint32_t vec_size = 1; \ + if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + vec_size = simple_op_node->value.type->traits.numeric.vector.component_count; \ + } \ + SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0]; \ + SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1]; \ + EVALUATE_OPERAND(operand1, res, CLEANUP) \ + EVALUATE_OPERAND(operand2, res, CLEANUP) \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->value.data.numeric.vector.value[i].undefined_value \ + || operand2->value.data.numeric.vector.value[i].undefined_value) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + switch ((simple_op_node)->value.type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + { \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value \ + operation operand2->value.data.numeric.vector.value[i].value.uint32_bool_value; \ + if (operand2->value.data.numeric.vector.value[i].value.uint32_bool_value == 0) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + } \ + break; \ + case 64: \ + { \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint64_value \ + = operand1->value.data.numeric.vector.value[i].value.uint64_value \ + operation operand2->value.data.numeric.vector.value[i].value.uint64_value; \ + if (operand2->value.data.numeric.vector.value[i].value.uint64_value == 0) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + } \ + break; \ + } \ + } \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: \ + { \ + SpvReflectPrvNode* p_parser_node = simple_op_node->instruction_private.uninitialized; \ + CHECK_INSTRUCTION_SIZE(p_parser_node, 6) \ + (simple_op_node)->num_id_operands = 2; \ + (simple_op_node)->num_literal_words = 0; \ + \ + /* check result type */ \ + CHECK_IS_INTEGER_TYPE((simple_op_node), res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node), res, CLEANUP) \ + if ((simple_op_node)->value.type->traits.numeric.scalar.signedness) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: \ + { \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), simple_op_node, 4, simple_op_node->id_operands[0], res, CLEANUP) \ + if((simple_op_node)->id_operands[0]->value.type->id != (simple_op_node)->value.type->id) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), simple_op_node, 5, simple_op_node->id_operands[1], res, CLEANUP) \ + if((simple_op_node)->id_operands[1]->value.type->id != (simple_op_node)->value.type->id) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (simple_op_node), (simple_op_node)->id_operands[0], (simple_op_node)->id_operands[1], res, CLEANUP) \ + } \ + break; \ + } \ } #define SHIFT_OP_32_BIT_HOOK_PRE @@ -5951,267 +5938,251 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect #define SHIFT_OP_32_BIT_HOOK_POST #define SHIFT_OP_64_BIT_HOOK_POST -#define DO_SHIFT_OPERATION(simple_op_eval, simple_op_node, operation, res, CLEANUP) \ -{ \ - switch (evaluation_mode) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR;\ - goto CLEANUP;\ - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL:\ - {\ - uint32_t vec_size = 1;\ - if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) {\ - vec_size = simple_op_node->value.type->traits.numeric.vector.component_count;\ - }\ - SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0];\ - SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1];\ - EVALUATE_OPERAND(operand1, res, CLEANUP)\ - EVALUATE_OPERAND(operand2, res, CLEANUP)\ - uint32_t res_width = (p_node)->value.type->traits.numeric.scalar.width;\ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1->value.data.numeric.vector.value[i].undefined_value \ - || operand2->value.data.numeric.vector.value[i].undefined_value) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - /* load the shift number, set undefined flag if larger than result width*/ \ - uint8_t shift_num; \ - switch (operand2->value.type->traits.numeric.scalar.width) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - case 32: \ - { \ - uint32_t shift = operand2->value.data.numeric.vector.value[i].value.uint32_bool_value; \ - if (operand1->value.data.numeric.vector.value[i].undefined_value || shift >= res_width) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - shift_num = (uint8_t)shift; \ - } \ - break; \ - case 64: \ - { \ - uint64_t shift = operand2->value.data.numeric.vector.value[i].value.uint64_value; \ - if (operand1->value.data.numeric.vector.value[i].undefined_value || shift >= res_width) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - shift_num = (uint8_t)shift; \ - } \ - break; \ - } \ - switch (res_width) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - case 32: \ - { \ - uint32_t data = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value; \ - SHIFT_OP_32_BIT_HOOK_PRE \ - data operation##= shift_num; \ - SHIFT_OP_32_BIT_HOOK_POST \ - (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value = data; \ - } \ - break; \ - case 64: \ - { \ - uint64_t data = operand1->value.data.numeric.vector.value[i].value.uint64_value; \ - SHIFT_OP_64_BIT_HOOK_PRE \ - data operation##= shift_num; \ - SHIFT_OP_64_BIT_HOOK_POST \ - (simple_op_node)->value.data.numeric.vector.value[i].value.uint64_value = data; \ - } \ - break; \ - } \ - } \ - }\ - break; \ - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS:\ - {\ - CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ - simple_op_node->num_id_operands = 2;\ - simple_op_node->num_literal_words = 0;\ - \ - /* check result type */\ - CHECK_IS_INTEGER_TYPE(simple_op_node, res, CLEANUP)\ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node, res, CLEANUP)\ - }\ - break;\ - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS:\ - {\ - GET_OPERAND((simple_op_eval), simple_op_node, 4, p_node->id_operands[0], res, CLEANUP)\ - CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[0], res, CLEANUP)\ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP)\ - GET_OPERAND((simple_op_eval), p_node, 5, p_node->id_operands[1], res, CLEANUP)\ - CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[1], res, CLEANUP)\ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP)\ - \ - /* op1 and result must have same width */\ - CHECK_WIDTH_MATCH(simple_op_node, p_node->id_operands[0], res, CLEANUP)\ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP)\ - }\ - break;\ - }\ -} - -#define DO_BINARY_BOOLEAN_LOGICAL_OPERATION(simple_op_eval, simple_op_node, operation, res, CLEANUP) \ -{ \ - switch (evaluation_mode) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR;\ - goto CLEANUP;\ - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL:\ - {\ - uint32_t vec_size = 1;\ - if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) {\ - vec_size = simple_op_node->value.type->traits.numeric.vector.component_count;\ - }\ - SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0];\ - SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1];\ - EVALUATE_OPERAND(operand1, res, CLEANUP)\ - EVALUATE_OPERAND(operand2, res, CLEANUP)\ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1->value.data.numeric.vector.value[i].undefined_value \ - operation operand2->value.data.numeric.vector.value[i].undefined_value) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - /* write to correct offset */ \ - (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value \ - operation operand2->value.data.numeric.vector.value[i].value.uint32_bool_value; \ - } \ - }\ - break; \ - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS:\ - {\ - CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ - simple_op_node->num_id_operands = 2;\ - simple_op_node->num_literal_words = 0;\ - \ - /* check result type */\ - CHECK_IS_BOOLEAN_TYPE((simple_op_node), res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node), res, CLEANUP) \ - if ((simple_op_node)->value.type->traits.numeric.scalar.signedness) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - }\ - break;\ - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS:\ - {\ - GET_OPERAND((simple_op_eval), simple_op_node, 4, p_node->id_operands[0], res, CLEANUP)\ - CHECK_IS_BOOLEAN_TYPE(simple_op_node->id_operands[0], res, CLEANUP)\ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP)\ - GET_OPERAND((simple_op_eval), p_node, 5, p_node->id_operands[1], res, CLEANUP)\ - CHECK_IS_BOOLEAN_TYPE(simple_op_node->id_operands[1], res, CLEANUP)\ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP)\ - \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP)\ - }\ - break;\ - }\ -} - -#define DO_BINARY_INTEGER_LOGICAL_OPERATION(simple_op_eval, simple_op_node, operation, _32bit_member, _64bit_member, res, CLEANUP) \ -{ \ - switch (evaluation_mode) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR;\ - goto CLEANUP;\ - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL:\ - {\ - uint32_t vec_size = 1;\ - if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) {\ - vec_size = simple_op_node->value.type->traits.numeric.vector.component_count;\ - }\ - SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0];\ - SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1];\ - EVALUATE_OPERAND(operand1, res, CLEANUP)\ - EVALUATE_OPERAND(operand2, res, CLEANUP)\ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1->value.data.numeric.vector.value[i].undefined_value \ - || operand2->value.data.numeric.vector.value[i].undefined_value) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - switch (operand1->value.type->traits.numeric.scalar.width) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - case 32: \ - (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1->value.data.numeric.vector.value[i].value.##_32bit_member \ - operation operand2->value.data.numeric.vector.value[i].value.##_32bit_member; \ - break; \ - case 64: \ - (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1->value.data.numeric.vector.value[i].value.##_64bit_member \ - operation operand2->value.data.numeric.vector.value[i].value.##_64bit_member; \ - break; \ - } \ - } \ - }\ - break; \ - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS:\ - {\ - CHECK_INSTRUCTION_SIZE(simple_op_node, 6) \ - simple_op_node->num_id_operands = 2;\ - simple_op_node->num_literal_words = 0;\ - \ - /* check result type */\ - CHECK_IS_BOOLEAN_TYPE((simple_op_node), res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node), res, CLEANUP) \ - if ((simple_op_node)->value.type->traits.numeric.scalar.signedness) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - }\ - break;\ - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS:\ - {\ - GET_OPERAND((simple_op_eval), simple_op_node, 4, p_node->id_operands[0], res, CLEANUP)\ - CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[0], res, CLEANUP)\ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP)\ - GET_OPERAND((simple_op_eval), p_node, 5, p_node->id_operands[1], res, CLEANUP)\ - CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[1], res, CLEANUP)\ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP)\ - \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP)\ - }\ - break;\ - }\ -} - -#define DO_BINARY_UINTEGER_LOGICAL_OPERATION(simple_op_eval, simple_op_node, operation, res, CLEANUP) \ - DO_BINARY_INTEGER_LOGICAL_OPERATION(simple_op_eval, simple_op_node, operation, uint32_bool_value, uint64_value, res, CLEANUP) -#define DO_BINARY_SINTEGER_LOGICAL_OPERATION(simple_op_eval, simple_op_node, operation, res, CLEANUP) \ - DO_BINARY_INTEGER_LOGICAL_OPERATION(simple_op_eval, simple_op_node, operation, sint32_value, sint64_value, res, CLEANUP) - - -#ifdef _MSC_VER -#define SPIRV_REFLECT_FORCEINLINE __forceinline -#else -#define SPIRV_REFLECT_FORCEINLINE __attribute__((always_inline)) inline -#endif - - -static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node, SpvReflectEvaluationState evaluation_mode); -static SpvReflectResult EvaluateResult_Do(SpvReflectPrvEvaluationNode* p_node) { - return EvaluateResultImpl(NULL, p_node, SPIRV_REFLECT_EVALUATION_MODE_NORMAL); -} -static SpvReflectResult EvaluateResult_1PASS(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node){ - return EvaluateResultImpl(p_eval, p_node, SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS); -} -static SpvReflectResult EvaluateResult_2PASS(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node) { - return EvaluateResultImpl(p_eval, p_node, SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS); -} +#define DO_SHIFT_OPERATION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP) \ +{ \ + switch (mode) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; \ + goto CLEANUP; \ + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: \ + { \ + uint32_t vec_size = 1; \ + if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + vec_size = simple_op_node->value.type->traits.numeric.vector.component_count; \ + } \ + SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0]; \ + SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1]; \ + EVALUATE_OPERAND(operand1, res, CLEANUP) \ + EVALUATE_OPERAND(operand2, res, CLEANUP) \ + uint32_t res_width = ((simple_op_node))->value.type->traits.numeric.scalar.width; \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->value.data.numeric.vector.value[i].undefined_value \ + || operand2->value.data.numeric.vector.value[i].undefined_value) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + /* load the shift number, set undefined flag if larger than result width*/ \ + uint8_t shift_num; \ + switch (operand2->value.type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + { \ + uint32_t shift = operand2->value.data.numeric.vector.value[i].value.uint32_bool_value; \ + if (operand1->value.data.numeric.vector.value[i].undefined_value || shift >= res_width) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + shift_num = (uint8_t)shift; \ + } \ + break; \ + case 64: \ + { \ + uint64_t shift = operand2->value.data.numeric.vector.value[i].value.uint64_value; \ + if (operand1->value.data.numeric.vector.value[i].undefined_value || shift >= res_width) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + shift_num = (uint8_t)shift; \ + } \ + break; \ + } \ + switch (res_width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + { \ + uint32_t data = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value; \ + SHIFT_OP_32_BIT_HOOK_PRE \ + data operation##= shift_num; \ + SHIFT_OP_32_BIT_HOOK_POST \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value = data; \ + } \ + break; \ + case 64: \ + { \ + uint64_t data = operand1->value.data.numeric.vector.value[i].value.uint64_value; \ + SHIFT_OP_64_BIT_HOOK_PRE \ + data operation##= shift_num; \ + SHIFT_OP_64_BIT_HOOK_POST \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint64_value = data; \ + } \ + break; \ + } \ + } \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: \ + { \ + SpvReflectPrvNode* p_parser_node = simple_op_node->instruction_private.uninitialized; \ + CHECK_INSTRUCTION_SIZE(p_parser_node, 6) \ + simple_op_node->num_id_operands = 2; \ + simple_op_node->num_literal_words = 0; \ + \ + /* check result type */ \ + CHECK_IS_INTEGER_TYPE(simple_op_node, res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node, res, CLEANUP) \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: \ + { \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), simple_op_node, 4, (simple_op_node)->id_operands[0], res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), (simple_op_node), 5, (simple_op_node)->id_operands[1], res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ + \ + /* op1 and result must have same width */ \ + CHECK_WIDTH_MATCH(simple_op_node, (simple_op_node)->id_operands[0], res, CLEANUP) \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ + } \ + break; \ + } \ +} + +#define DO_BINARY_BOOLEAN_LOGICAL_OPERATION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP) \ +{ \ + switch (mode) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; \ + goto CLEANUP; \ + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: \ + { \ + uint32_t vec_size = 1; \ + if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + vec_size = simple_op_node->value.type->traits.numeric.vector.component_count; \ + } \ + SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0]; \ + SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1]; \ + EVALUATE_OPERAND(operand1, res, CLEANUP) \ + EVALUATE_OPERAND(operand2, res, CLEANUP) \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->value.data.numeric.vector.value[i].undefined_value \ + operation operand2->value.data.numeric.vector.value[i].undefined_value) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + /* write to correct offset */ \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value \ + operation operand2->value.data.numeric.vector.value[i].value.uint32_bool_value; \ + } \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: \ + { \ + SpvReflectPrvNode* p_parser_node = simple_op_node->instruction_private.uninitialized; \ + CHECK_INSTRUCTION_SIZE(p_parser_node, 6) \ + simple_op_node->num_id_operands = 2; \ + simple_op_node->num_literal_words = 0; \ + \ + /* check result type */ \ + CHECK_IS_BOOLEAN_TYPE((simple_op_node), res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node), res, CLEANUP) \ + if ((simple_op_node)->value.type->traits.numeric.scalar.signedness) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: \ + { \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), simple_op_node, 4, (simple_op_node)->id_operands[0], res, CLEANUP) \ + CHECK_IS_BOOLEAN_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), (simple_op_node), 5, (simple_op_node)->id_operands[1], res, CLEANUP) \ + CHECK_IS_BOOLEAN_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ + \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ + } \ + break; \ + } \ +} + +#define DO_BINARY_INTEGER_LOGICAL_OPERATION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, _32bit_member, _64bit_member, res, CLEANUP) \ +{ \ + switch (mode) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; \ + goto CLEANUP; \ + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: \ + { \ + uint32_t vec_size = 1; \ + if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + vec_size = simple_op_node->value.type->traits.numeric.vector.component_count; \ + } \ + SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0]; \ + SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1]; \ + EVALUATE_OPERAND(operand1, res, CLEANUP) \ + EVALUATE_OPERAND(operand2, res, CLEANUP) \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->value.data.numeric.vector.value[i].undefined_value \ + || operand2->value.data.numeric.vector.value[i].undefined_value) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + switch (operand1->value.type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1->value.data.numeric.vector.value[i].value.##_32bit_member \ + operation operand2->value.data.numeric.vector.value[i].value.##_32bit_member; \ + break; \ + case 64: \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1->value.data.numeric.vector.value[i].value.##_64bit_member \ + operation operand2->value.data.numeric.vector.value[i].value.##_64bit_member; \ + break; \ + } \ + } \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: \ + { \ + SpvReflectPrvNode* p_parser_node = simple_op_node->instruction_private.uninitialized; \ + CHECK_INSTRUCTION_SIZE(p_parser_node, 6) \ + simple_op_node->num_id_operands = 2; \ + simple_op_node->num_literal_words = 0; \ + \ + /* check result type */ \ + CHECK_IS_BOOLEAN_TYPE((simple_op_node), res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node), res, CLEANUP) \ + if ((simple_op_node)->value.type->traits.numeric.scalar.signedness) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: \ + { \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), simple_op_node, 4, (simple_op_node)->id_operands[0], res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), (simple_op_node), 5, (simple_op_node)->id_operands[1], res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ + \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ + } \ + break; \ + } \ +} + +#define DO_BINARY_UINTEGER_LOGICAL_OPERATION(mode, p_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP) \ + DO_BINARY_INTEGER_LOGICAL_OPERATION(mode, p_parser,simple_op_eval, simple_op_node, operation, uint32_bool_value, uint64_value, res, CLEANUP) +#define DO_BINARY_SINTEGER_LOGICAL_OPERATION(mode, p_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP) \ + DO_BINARY_INTEGER_LOGICAL_OPERATION(mode, p_parser,simple_op_eval, simple_op_node, operation, sint32_value, sint64_value, res, CLEANUP) // change implementation to use SpvReflectPrvEvaluationNode* and SpvReflectEvaluation* p_eval as the only two parameters // node is the node to evaluate, p_eval != NULL signals AST building. 2 passes of ast building will be // labeled in p_eval's flags // This function should be inline, and outside should call the _1PASS, _2PASS, _EVAL versions, so compiler can // remove the inner branches... -static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node, SpvReflectEvaluationState evaluation_mode) +static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node, SpvReflectEvaluationMode evaluation_mode, SpvReflectPrvParser* p_parser) { if (!p_node) return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; @@ -6343,7 +6314,8 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } // check instruction size - if (p_node->word_count != 3 + vec_size) { + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + if (p_parser_node->word_count != 3 + vec_size) { res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; goto CLEANUP; } @@ -6353,7 +6325,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: { for (uint32_t i = 0; i < p_node->num_id_operands; ++i) { - GET_OPERAND(p_eval, p_node, 3 + i, p_node->id_operands[i], res, CLEANUP) + GET_OPERAND(p_parser, p_eval, p_node, 3 + i, p_node->id_operands[i], res, CLEANUP) // check type compatibility if (p_node->id_operands[i]->value.type->id != p_node->value.type->component_type_id) { res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; @@ -6377,7 +6349,8 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE goto CLEANUP; } if (evaluation_mode == SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS) { - EVAL_CHECKED_READU32(p_eval, p_node->word_offset + 3, p_node->specOp, res, CLEANUP); + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 3, p_node->specOp, res, CLEANUP); } switch (p_node->specOp) { @@ -6407,7 +6380,8 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE break; case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: { - CHECK_INSTRUCTION_SIZE(p_node, 4) + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + CHECK_INSTRUCTION_SIZE(p_parser_node, 4) p_node->num_id_operands = 0; p_node->num_literal_words = 0; if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VOID) { @@ -6484,7 +6458,8 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE break; case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: { - CHECK_INSTRUCTION_SIZE(p_node, 5) + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + CHECK_INSTRUCTION_SIZE(p_parser_node, 5) p_node->num_id_operands = 1; p_node->num_literal_words = 0; @@ -6495,7 +6470,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE break; case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: { - GET_OPERAND(p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) + GET_OPERAND(p_parser, p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) CHECK_IS_INTEGER_TYPE(p_node->id_operands[0], res, CLEANUP) CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) @@ -6574,7 +6549,8 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE break; case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: { - CHECK_INSTRUCTION_SIZE(p_node, 5) + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + CHECK_INSTRUCTION_SIZE(p_parser_node, 5) p_node->num_id_operands = 1; p_node->num_literal_words = 0; @@ -6585,7 +6561,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE break; case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: { - GET_OPERAND(p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) + GET_OPERAND(p_parser, p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) CHECK_IS_INTEGER_TYPE(p_node->id_operands[0], res, CLEANUP) CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) @@ -6657,7 +6633,8 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE break; case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: { - CHECK_INSTRUCTION_SIZE(p_node, 5) + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + CHECK_INSTRUCTION_SIZE(p_parser_node, 5) p_node->num_id_operands = 1; p_node->num_literal_words = 0; @@ -6668,7 +6645,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE break; case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: { - GET_OPERAND(p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) + GET_OPERAND(p_parser, p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) CHECK_IS_FLOAT_TYPE(p_node->id_operands[0], res, CLEANUP) CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) @@ -6685,7 +6662,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE #undef SIMPLE_UNARY_OP_64_BIT_HOOK #define SIMPLE_UNARY_OP_32_BIT_HOOK {data = -data;} #define SIMPLE_UNARY_OP_64_BIT_HOOK {data = -data;} - DO_SIMPLE_UNARY_INTEGER_OPERATION(p_eval, p_node, res, CLEANUP) + DO_SIMPLE_UNARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, res, CLEANUP) #undef SIMPLE_UNARY_OP_32_BIT_HOOK #undef SIMPLE_UNARY_OP_64_BIT_HOOK #define SIMPLE_UNARY_OP_32_BIT_HOOK @@ -6697,7 +6674,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE #undef SIMPLE_UNARY_OP_64_BIT_HOOK #define SIMPLE_UNARY_OP_32_BIT_HOOK data ^= 0xffffffff; #define SIMPLE_UNARY_OP_64_BIT_HOOK data ^= 0xffffffffffffffff; - DO_SIMPLE_UNARY_INTEGER_OPERATION(p_eval, p_node, res, CLEANUP) + DO_SIMPLE_UNARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, res, CLEANUP) #undef SIMPLE_UNARY_OP_32_BIT_HOOK #undef SIMPLE_UNARY_OP_64_BIT_HOOK #define SIMPLE_UNARY_OP_32_BIT_HOOK @@ -6706,25 +6683,25 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE case SpvOpIAdd: // integer add. // subtraction result is the same for 2-compliment - DO_SIMPLE_BINARY_INTEGER_OPERATION(p_eval, p_node, +, res, CLEANUP) + DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, +, res, CLEANUP) break; case SpvOpISub: // integer subtract. // subtraction result is the same for 2-compliment - DO_SIMPLE_BINARY_INTEGER_OPERATION(p_eval, p_node, -, res, CLEANUP) + DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, -, res, CLEANUP) break; case SpvOpIMul: // integer multiply... // imul instruction on x86, signed and unsigned have no difference in result // except for how they overflow. - DO_SIMPLE_BINARY_INTEGER_OPERATION(p_eval, p_node, *, res, CLEANUP) + DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, *, res, CLEANUP) break; case SpvOpUDiv: // unsigned divide // All operand must be same unsigned integer scalar or vector type. // x86 div instruction // emits undefined value if divide by zero - DO_UNSIGNED_INTEGER_DIVISION(p_eval, p_node, /, res, CLEANUP) + DO_UNSIGNED_INTEGER_DIVISION(evaluation_mode, p_parser, p_eval, p_node, /, res, CLEANUP) break; case SpvOpSDiv: // signed divide @@ -6735,14 +6712,14 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE #undef SIMPLE_BINARY_OP_32_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ - p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ + p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ } #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_64_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ - p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ + p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ } - DO_SIMPLE_BINARY_INTEGER_OPERATION(p_eval, p_node, /, res, CLEANUP) + DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, /, res, CLEANUP) #undef SIMPLE_BINARY_OP_32_BIT_HOOK #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK @@ -6751,21 +6728,21 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE case SpvOpUMod: // unsigned modulo // all types must be same unsigned integer scalar or vector type. - DO_UNSIGNED_INTEGER_DIVISION( p_eval, p_node, %, res, CLEANUP) + DO_UNSIGNED_INTEGER_DIVISION(evaluation_mode, p_parser, p_eval, p_node, %, res, CLEANUP) break; case SpvOpSRem: // just the result of % operator. #undef SIMPLE_BINARY_OP_32_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ - p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ + p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ } #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_64_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ - p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ + p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ } - DO_SIMPLE_BINARY_INTEGER_OPERATION(p_eval, p_node, %, res, CLEANUP) + DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, %, res, CLEANUP) #undef SIMPLE_BINARY_OP_32_BIT_HOOK #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK @@ -6776,7 +6753,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE #undef SIMPLE_BINARY_OP_32_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ - p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ + p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ } \ else if (data != 0) { \ int sign1 = 0, sign2 = 0; \ @@ -6790,7 +6767,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_64_BIT_HOOK \ if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ - p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ + p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ } \ else if (data != 0) { \ int sign1 = 0, sign2 = 0; \ @@ -6801,7 +6778,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE data += data2; \ } \ } - DO_SIMPLE_BINARY_INTEGER_OPERATION(p_eval, p_node, %, res, CLEANUP) + DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, %, res, CLEANUP) #undef SIMPLE_BINARY_OP_32_BIT_HOOK #undef SIMPLE_BINARY_OP_64_BIT_HOOK #define SIMPLE_BINARY_OP_32_BIT_HOOK @@ -6809,7 +6786,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE break; case SpvOpShiftRightLogical: // zero fill right shift. Just >> in c - DO_SHIFT_OPERATION(p_eval, p_node, >>, res, CLEANUP) + DO_SHIFT_OPERATION(evaluation_mode, p_parser, p_eval, p_node, >>, res, CLEANUP) break; case SpvOpShiftRightArithmetic: // fill with sign of original number. @@ -6829,7 +6806,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE uint64_t fill = 0xffffffffffffffff << (64 - shift_num); \ data |= fill; \ } - DO_SHIFT_OPERATION(p_eval, p_node, >> , res, CLEANUP) + DO_SHIFT_OPERATION(evaluation_mode, p_parser, p_eval, p_node, >> , res, CLEANUP) #undef SHIFT_OP_32_BIT_HOOK_PRE #undef SHIFT_OP_64_BIT_HOOK_PRE #undef SHIFT_OP_32_BIT_HOOK_POST @@ -6841,16 +6818,16 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE break; case SpvOpShiftLeftLogical: // zero fill left shift. Just << in c - DO_SHIFT_OPERATION(p_eval, p_node, << , res, CLEANUP) + DO_SHIFT_OPERATION(evaluation_mode, p_parser, p_eval, p_node, << , res, CLEANUP) break; case SpvOpBitwiseOr: - DO_SIMPLE_BINARY_INTEGER_OPERATION(p_eval, p_node, |, res, CLEANUP) + DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, |, res, CLEANUP) break; case SpvOpBitwiseXor: - DO_SIMPLE_BINARY_INTEGER_OPERATION(p_eval, p_node, ^ , res, CLEANUP) + DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, ^ , res, CLEANUP) break; case SpvOpBitwiseAnd: - DO_SIMPLE_BINARY_INTEGER_OPERATION(p_eval, p_node, & , res, CLEANUP) + DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, & , res, CLEANUP) break; case SpvOpVectorShuffle: @@ -6865,21 +6842,17 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE { SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; SpvReflectPrvEvaluationNode* operand2 = p_node->id_operands[1]; - EVALUATE_OPERAND(operand1, res, CLEANUP) - EVALUATE_OPERAND(operand2, res, CLEANUP) for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { - uint32_t mapped_component = p_node->literal_words[i]; - if (mapped_component == 0xFFFFFFFF) { + uint8_t mapped_component = p_node->instruction_private.vector_shuffle.idx[i]; + if (mapped_component == 0xff) { result->data.numeric.vector.value[i].undefined_value = 1; } - else if (mapped_component >= operand1->value.type->traits.numeric.vector.component_count + operand2->value.type->traits.numeric.vector.component_count) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; - goto CLEANUP; - } else if (mapped_component < operand1->value.type->traits.numeric.vector.component_count) { + EVALUATE_OPERAND(operand1, res, CLEANUP) result->data.numeric.vector.value[i] = operand1->value.data.numeric.vector.value[mapped_component]; } else { + EVALUATE_OPERAND(operand2, res, CLEANUP) result->data.numeric.vector.value[i] = operand2->value.data.numeric.vector.value[mapped_component - operand1->value.type->traits.numeric.vector.component_count]; } } @@ -6894,19 +6867,22 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE goto CLEANUP; } - CHECK_INSTRUCTION_SIZE(p_node, 6 + p_node->value.type->traits.numeric.vector.component_count) + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + CHECK_INSTRUCTION_SIZE(p_parser_node, 6 + p_node->value.type->traits.numeric.vector.component_count) + + if (p_node->value.type->traits.numeric.vector.component_count > SPV_REFLECT_MAX_VECTOR_DIMS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } p_node->num_id_operands = 2; - p_node->num_literal_words = p_node->value.type->traits.numeric.vector.component_count; + p_node->num_literal_words = 0; - // check result type - CHECK_IS_FLOAT_TYPE(p_node, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) } break; case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: { - GET_OPERAND(p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) + GET_OPERAND(p_parser, p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) if (!(p_node->id_operands[0]->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; @@ -6916,8 +6892,12 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; } + if (p_node->id_operands[0]->value.type->traits.numeric.vector.component_count > SPV_REFLECT_MAX_VECTOR_DIMS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } - GET_OPERAND(p_eval,p_node, 5, p_node->id_operands[1], res, CLEANUP) + GET_OPERAND(p_parser, p_eval,p_node, 5, p_node->id_operands[1], res, CLEANUP) CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[1], res, CLEANUP) if (!(p_node->id_operands[1]->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; @@ -6927,9 +6907,27 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; } + if (p_node->id_operands[1]->value.type->traits.numeric.vector.component_count > SPV_REFLECT_MAX_VECTOR_DIMS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } - for(uint32_t i = 0; inum_literal_words; ++i) { - EVAL_CHECKED_READU32(p_eval, p_node->word_offset + 6 + i, p_node->literal_words[i], res, CLEANUP); + uint32_t max_index = p_node->id_operands[0]->value.type->traits.numeric.vector.component_count + p_node->id_operands[1]->value.type->traits.numeric.vector.component_count; + + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + for(uint32_t i = 0; i< p_node->value.type->traits.numeric.vector.component_count; ++i) { + uint32_t idx; + EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 6 + i, idx, res, CLEANUP); + if (idx == 0xffffffff) { + p_node->instruction_private.vector_shuffle.idx[i] = 0xff; + } + else { + if (idx >= max_index) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + p_node->instruction_private.vector_shuffle.idx[i] = (uint8_t)idx; + } } } break; @@ -6949,19 +6947,8 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: { EVALUATE_OPERAND(p_node->id_operands[0], res, CLEANUP) - SpvReflectValueData* current_data = &p_node->id_operands[0]->value.data; - SpvReflectTypeDescription* current_type = p_node->id_operands[0]->value.type; - for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { - uint32_t member_index = p_node->literal_words[i]; - res = GetMemberByIndex(p_eval->member_type_finder, current_data, current_type, member_index, ¤t_data, ¤t_type); - if (res != SPV_REFLECT_RESULT_SUCCESS) { - goto CLEANUP; - } - } - if (current_type->id != p_node->value.type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } + SpvReflectValueData* current_data = p_node->instruction_private.composite_extract.src_data; + SpvReflectTypeDescription* current_type = p_node->instruction_private.composite_extract.src_type; res = CopyValueData(current_type, &result->data, current_data); if (res != SPV_REFLECT_RESULT_SUCCESS) { goto CLEANUP; @@ -6981,28 +6968,30 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; } - if(p_node->word_count < 5) { + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + if(p_parser_node->word_count < 5) { res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; goto CLEANUP; } p_node->num_id_operands = 1; - p_node->num_literal_words = p_node->word_count - 5; + p_node->num_literal_words = p_parser_node->word_count - 5; } break; case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: { - GET_OPERAND(p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) + GET_OPERAND(p_parser, p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) if (p_node->id_operands[0]->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; } + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; SpvReflectValueData* current_data = &p_node->id_operands[0]->value.data; SpvReflectTypeDescription* current_type = p_node->id_operands[0]->value.type; for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { uint32_t member_index; - EVAL_CHECKED_READU32(p_eval, p_node->word_offset + 5 + i, member_index, res, CLEANUP); + EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 5 + i, member_index, res, CLEANUP); p_node->literal_words[i] = member_index; res = GetMemberByIndex(p_eval->member_type_finder, current_data, current_type, member_index, ¤t_data, ¤t_type); if (res != SPV_REFLECT_RESULT_SUCCESS) { @@ -7013,6 +7002,9 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; } + + p_node->instruction_private.composite_extract.src_data = current_data; + p_node->instruction_private.composite_extract.src_type = current_type; } break; } @@ -7033,23 +7025,10 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE if (res != SPV_REFLECT_RESULT_SUCCESS) { goto CLEANUP; } - SpvReflectValueData* current_data = &result->data; - SpvReflectTypeDescription* current_type = result->type; - for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { - uint32_t member_index; - EVAL_CHECKED_READU32(p_eval, p_node->word_offset + 6 + i, member_index, res, CLEANUP); - p_node->literal_words[i] = member_index; - res = GetMemberByIndex(p_eval->member_type_finder, current_data, current_type, member_index, ¤t_data, ¤t_type); - if (res != SPV_REFLECT_RESULT_SUCCESS) { - goto CLEANUP; - } - } - if (current_type->id != p_node->id_operands[0]->value.type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } + EVALUATE_OPERAND(p_node->id_operands[1], res, CLEANUP) - res = CopyValueData(current_type, current_data, &p_node->id_operands[1]->value.data); + res = CopyValueData(p_node->instruction_private.composite_insert.dst_type, + p_node->instruction_private.composite_insert.dst_data, &p_node->id_operands[1]->value.data); if (res != SPV_REFLECT_RESULT_SUCCESS) { goto CLEANUP; } @@ -7069,25 +7048,26 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE goto CLEANUP; } - if (p_node->word_count < 6) { + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + if (p_parser_node->word_count < 6) { res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; goto CLEANUP; } p_node->num_id_operands = 2; - p_node->num_literal_words = p_node->word_count - 6; + p_node->num_literal_words = p_parser_node->word_count - 6; } break; case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: { // the value to modify to - GET_OPERAND(p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) + GET_OPERAND(p_parser, p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) if (p_node->id_operands[0]->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; } // the original value - GET_OPERAND(p_eval, p_node, 5, p_node->id_operands[1], res, CLEANUP) + GET_OPERAND(p_parser, p_eval, p_node, 5, p_node->id_operands[1], res, CLEANUP) if (p_node->id_operands[1]->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; @@ -7097,12 +7077,12 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; } - + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; SpvReflectValueData* current_data = &result->data; SpvReflectTypeDescription* current_type = result->type; for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { uint32_t member_index; - EVAL_CHECKED_READU32(p_eval, p_node->word_offset + 6 + i, member_index, res, CLEANUP); + EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 6 + i, member_index, res, CLEANUP); p_node->literal_words[i] = member_index; res = GetMemberByIndex(p_eval->member_type_finder, current_data, current_type, member_index, ¤t_data, ¤t_type); if (res != SPV_REFLECT_RESULT_SUCCESS) { @@ -7113,6 +7093,9 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; } + + p_node->instruction_private.composite_insert.dst_data = current_data; + p_node->instruction_private.composite_insert.dst_type = current_type; } break; } @@ -7120,10 +7103,10 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE break; case SpvOpLogicalOr: - DO_BINARY_BOOLEAN_LOGICAL_OPERATION(p_eval, p_node, ||, res, CLEANUP) + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, ||, res, CLEANUP) break; case SpvOpLogicalAnd: - DO_BINARY_BOOLEAN_LOGICAL_OPERATION(p_eval, p_node, && , res, CLEANUP) + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, && , res, CLEANUP) break; case SpvOpLogicalNot: { @@ -7149,7 +7132,8 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE break; case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: { - CHECK_INSTRUCTION_SIZE(p_node, 5) + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + CHECK_INSTRUCTION_SIZE(p_parser_node, 5) p_node->num_id_operands = 1; p_node->num_literal_words = 0; @@ -7164,7 +7148,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE break; case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: { - GET_OPERAND(p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) + GET_OPERAND(p_parser, p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) CHECK_IS_BOOLEAN_TYPE(p_node->id_operands[0], res, CLEANUP) CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) @@ -7176,10 +7160,10 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE } break; case SpvOpLogicalEqual: - DO_BINARY_BOOLEAN_LOGICAL_OPERATION(p_eval, p_node, ==, res, CLEANUP) + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, ==, res, CLEANUP) break; case SpvOpLogicalNotEqual: - DO_BINARY_BOOLEAN_LOGICAL_OPERATION(p_eval, p_node, != , res, CLEANUP) + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, != , res, CLEANUP) break; case SpvOpSelect: // same as c/cpp code: a ? b : c; @@ -7237,7 +7221,8 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE break; case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: { - CHECK_INSTRUCTION_SIZE((p_node), 7) + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + CHECK_INSTRUCTION_SIZE(p_parser_node, 7) p_node->num_id_operands = 3; p_node->num_literal_words = 0; @@ -7250,17 +7235,17 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE break; case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: { - GET_OPERAND(p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) + GET_OPERAND(p_parser, p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) CHECK_IS_BOOLEAN_TYPE(p_node->id_operands[0], res, CLEANUP) CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) - GET_OPERAND(p_eval, p_node, 5, p_node->id_operands[1], res, CLEANUP) + GET_OPERAND(p_parser, p_eval, p_node, 5, p_node->id_operands[1], res, CLEANUP) if (p_node->id_operands[1]->value.type->id != p_node->value.type->id) { res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; } - GET_OPERAND(p_eval, p_node, 6, p_node->id_operands[2], res, CLEANUP) + GET_OPERAND(p_parser, p_eval, p_node, 6, p_node->id_operands[2], res, CLEANUP) if (p_node->id_operands[2]->value.type->id != p_node->value.type->id) { res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; @@ -7286,34 +7271,34 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResultImpl(SpvReflectE } break; case SpvOpIEqual: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(p_eval, p_node, ==, res, CLEANUP) + DO_BINARY_UINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, ==, res, CLEANUP) break; case SpvOpINotEqual: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(p_eval, p_node, != , res, CLEANUP) + DO_BINARY_UINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, != , res, CLEANUP) break; case SpvOpULessThan: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(p_eval, p_node, < , res, CLEANUP) + DO_BINARY_UINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, < , res, CLEANUP) break; case SpvOpSLessThan: - DO_BINARY_SINTEGER_LOGICAL_OPERATION(p_eval, p_node, < , res, CLEANUP) + DO_BINARY_SINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, < , res, CLEANUP) break; case SpvOpUGreaterThan: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(p_eval, p_node, > , res, CLEANUP) + DO_BINARY_UINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, > , res, CLEANUP) break; case SpvOpSGreaterThan: - DO_BINARY_SINTEGER_LOGICAL_OPERATION(p_eval, p_node, > , res, CLEANUP) + DO_BINARY_SINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, > , res, CLEANUP) break; case SpvOpULessThanEqual: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(p_eval, p_node, <= , res, CLEANUP) + DO_BINARY_UINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, <= , res, CLEANUP) break; case SpvOpSLessThanEqual: - DO_BINARY_SINTEGER_LOGICAL_OPERATION(p_eval, p_node, <= , res, CLEANUP) + DO_BINARY_SINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, <= , res, CLEANUP) break; case SpvOpUGreaterThanEqual: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(p_eval, p_node, >= , res, CLEANUP) + DO_BINARY_UINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, >= , res, CLEANUP) break; case SpvOpSGreaterThanEqual: - DO_BINARY_SINTEGER_LOGICAL_OPERATION(p_eval, p_node, >= , res, CLEANUP) + DO_BINARY_SINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, >= , res, CLEANUP) break; // check shader capability... vulkan should assume this... @@ -7375,13 +7360,19 @@ SpvReflectEvaluation* spvReflectGetEvaluationInterface(SpvReflectShaderModule* p return p_module->_internal->evaluator; } -bool HaveNodeInTree(const SpvReflectPrvEvaluationNode* p_node_root, const SpvReflectPrvEvaluationNode* p_node_expected) +bool HaveNodeInTree(SpvReflectPrvEvaluationNode* p_node_root, const SpvReflectPrvEvaluationNode* p_node_expected, bool flag_changed) { if (p_node_root == p_node_expected) { + if (flag_changed) { + p_node_root->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED; + } return true; } for (uint32_t i = 0; i < p_node_root->num_id_operands; ++i) { - if (HaveNodeInTree(p_node_root->id_operands[i], p_node_expected)) { + if (HaveNodeInTree(p_node_root->id_operands[i], p_node_expected, flag_changed)) { + if (flag_changed) { + p_node_root->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED; + } return true; } } @@ -7435,7 +7426,8 @@ SpvReflectResult spvReflectSetSpecConstantValue(SpvReflectEvaluation* p_eval, ui p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED; // update state tracking here... for (uint32_t i = 0; i < p_eval->node_count; ++i) { - if (HaveNodeInTree(&p_eval->nodes[i], p_node)) { + if (p_eval->nodes[i].evaluation_state == SPV_REFLECT_EVALUATION_NODE_STATE_DONE + && HaveNodeInTree(&p_eval->nodes[i], p_node, true)) { p_eval->nodes[i].evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED; } } @@ -7473,7 +7465,7 @@ int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id if (!p_node) { return 0; } - return HaveNodeInTree(p_node, p_spec); + return HaveNodeInTree(p_node, p_spec, false); } diff --git a/spirv_reflect.h b/spirv_reflect.h index 1e54ad59..c745f7bf 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -109,8 +109,7 @@ SPV_REFLECT_MODULE_FLAG_EVALUATE_NO_COPY - use p_code for later typedef enum SpvReflectModuleFlagBits { SPV_REFLECT_MODULE_FLAG_NONE = 0x00000000, SPV_REFLECT_MODULE_FLAG_NO_COPY = 0x00000001, - SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT = 0x00000002, - SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT_NO_COPY = 0x00000004 + SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT = 0x00000002 } SpvReflectModuleFlagBits; typedef uint32_t SpvReflectModuleFlags; @@ -349,19 +348,14 @@ typedef struct SpvReflectTypeDescription { } SpvReflectTypeDescription; -/*! @struct SpvReflectSpecializationConstant - -*/ - -typedef uint16_t spv_reflect_float16_t; typedef struct SpvReflectScalarValueData { union { /* small types not implemented yet... */ + /* also remember float16 */ uint8_t uint8_value; int8_t sint8_value; uint16_t uint16_value; int16_t sint16_value; - spv_reflect_float16_t float16_value; /* types that are currently supported */ uint32_t uint32_bool_value; int32_t sint32_value; @@ -397,6 +391,9 @@ typedef struct SpvReflectValue { SpvReflectValueData data; }SpvReflectValue; +/*! @struct SpvReflectSpecializationConstant + +*/ typedef struct SpvReflectSpecializationConstant { uint32_t spirv_id; uint32_t constant_id; From 2b02ddbba8671916fc5d2f0f25bf683a8384c159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sat, 6 Aug 2022 21:42:01 +0800 Subject: [PATCH 17/44] Unify indentation --- spirv_reflect.c | 3634 +++++++++++++++++++++++------------------------ 1 file changed, 1787 insertions(+), 1847 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index c613022c..0481d4a1 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -218,72 +218,70 @@ typedef struct SpvReflectPrvParser { // clang-format on typedef enum SpvReflectEvaluationNodeState { - SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED = 0, - SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED = 1, - SPV_REFLECT_EVALUATION_NODE_STATE_PENDING = 2, - // for tracking recursion - SPV_REFLECT_EVALUATION_NODE_STATE_WORKING = 3, - SPV_REFLECT_EVALUATION_NODE_STATE_DONE = 4, - // for possible update tracking - SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED = 5, - // failed evaluation - SPV_REFLECT_EVALUATION_NODE_STATE_FAILED = 6 + SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED = 0, + SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED = 1, + SPV_REFLECT_EVALUATION_NODE_STATE_PENDING = 2, + // for tracking recursion + SPV_REFLECT_EVALUATION_NODE_STATE_WORKING = 3, + SPV_REFLECT_EVALUATION_NODE_STATE_DONE = 4, + SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED = 5, + SPV_REFLECT_EVALUATION_NODE_STATE_FAILED = 6 }SpvReflectEvaluationNodeState; // clang-format off +// need declaration here to use pointer type inside... typedef struct SpvReflectPrvEvaluationNode SpvReflectPrvEvaluationNode; typedef struct SpvReflectPrvEvaluationNode { - uint32_t result_id; - SpvOp op; - SpvOp specOp; - - SpvReflectEvaluationNodeState evaluation_state; - SpvReflectValue value; - - uint32_t specId; - - uint32_t num_id_operands; - SpvReflectPrvEvaluationNode** id_operands; - uint32_t num_literal_words; - uint32_t* literal_words; - - // add another 2 passes if need explicit initialization and free... - union InstructionPrivate { - // used only in preprocess passes to replace parser FindNode - SpvReflectPrvNode* uninitialized; - struct VectorShuffle { - uint8_t idx[SPV_REFLECT_MAX_VECTOR_DIMS]; - } vector_shuffle; - struct CompositeExtract { - SpvReflectTypeDescription* src_type; - SpvReflectValueData* src_data; - } composite_extract; - struct CompositeInsert { - SpvReflectTypeDescription* dst_type; - SpvReflectValueData* dst_data; - }composite_insert; - } instruction_private; + uint32_t result_id; + SpvOp op; + SpvOp specOp; + + SpvReflectEvaluationNodeState evaluation_state; + SpvReflectValue value; + + uint32_t specId; + + uint32_t num_id_operands; + SpvReflectPrvEvaluationNode** id_operands; + uint32_t num_literal_words; + uint32_t* literal_words; + + // add another 2 passes if need explicit initialization and free... + union InstructionPrivate { + // used only in preprocess passes to replace parser FindNode + SpvReflectPrvNode* uninitialized; + struct VectorShuffle { + uint8_t idx[SPV_REFLECT_MAX_VECTOR_DIMS]; + } vector_shuffle; + struct CompositeExtract { + SpvReflectTypeDescription* src_type; + SpvReflectValueData* src_data; + } composite_extract; + struct CompositeInsert { + SpvReflectTypeDescription* dst_type; + SpvReflectValueData* dst_data; + }composite_insert; + } instruction_private; } SpvReflectPrvEvaluationNode; // clang-format on // clang-format off typedef enum SpvReflectEvaluationMode { - SPIRV_REFLECT_EVALUATION_MODE_NORMAL = 0, - // traverse all branches, currently for OpSelect - SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS = 1, - SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS = 2, + SPIRV_REFLECT_EVALUATION_MODE_NORMAL = 0, + SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS = 1, + SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS = 2 } SpvReflectEvaluationMode; typedef struct SpvReflectEvaluation { - uint32_t node_count; - SpvReflectPrvEvaluationNode* nodes; + uint32_t node_count; + SpvReflectPrvEvaluationNode* nodes; - SpvReflectPrvEvaluationNode** id_operand_buffer; - uint32_t* literal_word_buffer; + SpvReflectPrvEvaluationNode** id_operand_buffer; + uint32_t* literal_word_buffer; - // ohh I hope I could decouple this... But FindType uses this... - // just a reference - SpvReflectShaderModule* member_type_finder; + // ohh I hope I could decouple this... But FindType uses this... + // just a reference + SpvReflectShaderModule* member_type_finder; } SpvReflectEvaluation; // clang-format on @@ -594,33 +592,33 @@ static SpvReflectPrvNode* FindNode( } static SpvReflectPrvEvaluationNode* FindEvaluationNode( - SpvReflectEvaluation* p_eval, - uint32_t result_id) + SpvReflectEvaluation* p_eval, + uint32_t result_id) { - SpvReflectPrvEvaluationNode* p_node = NULL; - for (size_t i = 0; i < p_eval->node_count; ++i) { - SpvReflectPrvEvaluationNode* p_elem = &(p_eval->nodes[i]); - if (p_elem->result_id == result_id) { - p_node = p_elem; - break; - } + SpvReflectPrvEvaluationNode* p_node = NULL; + for (size_t i = 0; i < p_eval->node_count; ++i) { + SpvReflectPrvEvaluationNode* p_elem = &(p_eval->nodes[i]); + if (p_elem->result_id == result_id) { + p_node = p_elem; + break; } - return p_node; + } + return p_node; } static SpvReflectPrvEvaluationNode* FindSpecIdNode( - SpvReflectEvaluation* p_eval, - uint32_t specid) + SpvReflectEvaluation* p_eval, + uint32_t specid) { - SpvReflectPrvEvaluationNode* p_node = NULL; - for (size_t i = 0; i < p_eval->node_count; ++i) { - SpvReflectPrvEvaluationNode* p_elem = &(p_eval->nodes[i]); - if (p_elem->specId == specid) { - p_node = p_elem; - break; - } + SpvReflectPrvEvaluationNode* p_node = NULL; + for (size_t i = 0; i < p_eval->node_count; ++i) { + SpvReflectPrvEvaluationNode* p_elem = &(p_eval->nodes[i]); + if (p_elem->specId == specid) { + p_node = p_elem; + break; } - return p_node; + } + return p_node; } static SpvReflectTypeDescription* FindType(const SpvReflectShaderModule* p_module, uint32_t type_id) @@ -3483,14 +3481,13 @@ static SpvReflectResult ParseExecutionModes( return SPV_REFLECT_RESULT_SUCCESS; } -#define EVAL_CHECKED_READU32(parser, word_offset, value, res, cleanup) \ - { \ - res = ReadU32(parser, \ - word_offset, (uint32_t*)&(value)); \ - if (res != SPV_REFLECT_RESULT_SUCCESS) { \ - goto cleanup; \ - } \ - } +#define EVAL_CHECKED_READU32(parser, word_offset, value, res, cleanup) \ +{ \ + res = ReadU32(parser, word_offset, (uint32_t*)&(value)); \ + if (res != SPV_REFLECT_RESULT_SUCCESS) { \ + goto cleanup; \ + } \ +} #define SCALAR_TYPE_FLAGS (SPV_REFLECT_TYPE_FLAG_BOOL | SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_FLOAT) #define SCALAR_DISALLOWED_FLAGS (~0 ^ SCALAR_TYPE_FLAGS) @@ -3500,59 +3497,32 @@ static SpvReflectResult ParseExecutionModes( #define COMPOSITE_TYPE_FLAGS (VECTOR_TYPE_FLAGS|SPV_REFLECT_TYPE_FLAG_MATRIX|SPV_REFLECT_TYPE_FLAG_STRUCT|SPV_REFLECT_TYPE_FLAG_ARRAY) #define COMPOSITE_DISALLOWED_FLAGS (~0 ^ COMPOSITE_TYPE_FLAGS) -// getting constant also happens before evaluation is created. -static SpvReflectResult EvalGetScalarConstant(const SpvReflectPrvParser* p_parser, SpvReflectPrvEvaluationNode* p_node) -{ - SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS; - if(p_node->value.type->type_flags & SCALAR_DISALLOWED_FLAGS) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - SpvReflectPrvNode* p_parser_node = FindNode(p_parser, p_node->result_id); - uint32_t low_word; - EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 3, low_word, result, CLEANUP); - // There is no alignment requirements in c/cpp for unions - if (p_node->value.type->traits.numeric.scalar.width == 32) { - memcpy(&p_node->value.data.numeric.scalar.value.uint32_bool_value, &low_word, 4); - } - else if (p_node->value.type->traits.numeric.scalar.width ==64) { - uint32_t high_word; - EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 4, high_word, result, CLEANUP); - uint64_t combined = low_word | (((uint64_t)high_word) << 32); - memcpy(&p_node->value.data.numeric.scalar.value.uint64_value, &combined, 8); - } - else { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - CLEANUP: - return result; -} - static SpvReflectResult ParserGetScalarConstant(const SpvReflectShaderModule* p_module, SpvReflectPrvParser* p_parser, SpvReflectPrvNode* p_node, SpvReflectScalarValueData* result, SpvReflectTypeDescription** type) { - SpvReflectTypeDescription* d_type = FindType(p_module, p_node->result_type_id); - if (!d_type) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; - - if (d_type->type_flags & SCALAR_DISALLOWED_FLAGS) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - uint32_t low_word; - CHECKED_READU32(p_parser, p_node->word_offset + 3, low_word); - // There is no alignment requirements in c/cpp for unions - if (d_type->traits.numeric.scalar.width == 32) { - memcpy(&result->value.uint32_bool_value, &low_word, 4); - } - else if (d_type->traits.numeric.scalar.width == 64) { - uint32_t high_word; - CHECKED_READU32(p_parser, p_node->word_offset + 4, high_word); - uint64_t combined = low_word | (((uint64_t)high_word) << 32); - memcpy(&result->value.uint64_value, &combined, 8); - } - else { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - *type = d_type; - return SPV_REFLECT_RESULT_SUCCESS; + SpvReflectTypeDescription* d_type = FindType(p_module, p_node->result_type_id); + if (!d_type) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; + + if (d_type->type_flags & SCALAR_DISALLOWED_FLAGS) return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + uint32_t low_word; + CHECKED_READU32(p_parser, p_node->word_offset + 3, low_word); + // There is no alignment requirements in c/cpp for unions + if (d_type->traits.numeric.scalar.width == 32) { + memcpy(&result->value.uint32_bool_value, &low_word, 4); + } + else if (d_type->traits.numeric.scalar.width == 64) { + uint32_t high_word; + CHECKED_READU32(p_parser, p_node->word_offset + 4, high_word); + uint64_t combined = low_word | (((uint64_t)high_word) << 32); + memcpy(&result->value.uint64_value, &combined, 8); + } + else { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + *type = d_type; + return SPV_REFLECT_RESULT_SUCCESS; } -#define MODULE_EVALUATION_FLAGS (SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT | SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT_NO_COPY) - #define IS_SPEC_LITERAL_OP(op_code)\ (((op_code) == SpvOpSpecConstantTrue) || ((op_code) == SpvOpSpecConstantFalse) || ((op_code) == SpvOpSpecConstant)) #define IS_LITERAL_OP(op_code)\ @@ -3565,10 +3535,6 @@ static SpvReflectResult ParserGetScalarConstant(const SpvReflectShaderModule* p_ || ((op_code) == SpvOpConstantPipeStorage) || ((op_code) == SpvOpSpecConstantCompositeContinuedINTEL)\ || ((op_code) == SpvOpConstantFunctionPointerINTEL) || ((op_code) == SpvOpConstantCompositeContinuedINTEL)) -// defined later.. -static SpvReflectSpecializationConstant* GetSpecContantById(const SpvReflectShaderModule* p_module, uint32_t constant_id); - - #ifdef _MSC_VER #define SPIRV_REFLECT_FORCEINLINE __forceinline #else @@ -3581,18 +3547,18 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect // may move type info into instruction info later, but now it seems not needed... static SpvReflectResult EvaluateResult_Do(SpvReflectPrvEvaluationNode* p_node) { - return EvaluateResult_Impl(NULL, p_node, SPIRV_REFLECT_EVALUATION_MODE_NORMAL, NULL); + return EvaluateResult_Impl(NULL, p_node, SPIRV_REFLECT_EVALUATION_MODE_NORMAL, NULL); } // 1 PASS parser needs to read specOp and check instruction size static SpvReflectResult EvaluateResult_1PASS(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node, SpvReflectPrvParser* p_parser) { - return EvaluateResult_Impl(p_eval, p_node, SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS, p_parser); + return EvaluateResult_Impl(p_eval, p_node, SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS, p_parser); } // 2 PASS needs parser to get id operands and literals static SpvReflectResult EvaluateResult_2PASS(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node, SpvReflectPrvParser* p_parser) { - return EvaluateResult_Impl(p_eval, p_node, SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS, p_parser); + return EvaluateResult_Impl(p_eval, p_node, SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS, p_parser); } static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) @@ -3672,7 +3638,7 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars } // need to evaluate expr later on... - if (p_module->_internal->module_flags & MODULE_EVALUATION_FLAGS) { + if (p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT) { p_module->_internal->evaluator = (SpvReflectEvaluation*)calloc(1, sizeof(SpvReflectEvaluation)); if(!p_module->_internal->evaluator){ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; @@ -3769,16 +3735,15 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars } } - return SPV_REFLECT_RESULT_SUCCESS; } static void DestroyEvaluator(SpvReflectEvaluation* evaluator) { - SafeFree(evaluator->nodes); + SafeFree(evaluator->nodes); - SafeFree(evaluator->id_operand_buffer); - SafeFree(evaluator->literal_word_buffer); + SafeFree(evaluator->id_operand_buffer); + SafeFree(evaluator->literal_word_buffer); } @@ -4333,7 +4298,6 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module) SafeFree(p_entry->execution_modes); } SafeFree(p_module->entry_points); - SafeFree(p_module->specialization_constants); // Push constants for (size_t i = 0; i < p_module->push_constant_block_count; ++i) { @@ -4356,7 +4320,9 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module) SafeFree(p_module->_internal->spirv_code); } - if (p_module->_internal->module_flags & MODULE_EVALUATION_FLAGS) { + SafeFree(p_module->specialization_constants); + + if (p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT) { DestroyEvaluator(p_module->_internal->evaluator); SafeFree(p_module->_internal->evaluator) } @@ -5540,124 +5506,112 @@ const char* spvReflectBlockVariableTypeName( return p_var->type_description->type_name; } - - -SpvReflectSpecializationConstant* GetSpecContantById(const SpvReflectShaderModule* p_module, uint32_t constant_id) -{ - for (uint32_t i = 0; i < p_module->specialization_constant_count; ++i) { - if (p_module->specialization_constants[i].constant_id == constant_id) { - return &p_module->specialization_constants[i]; - } - } - return NULL; -} - SpvReflectResult GetMemberByIndex(const SpvReflectShaderModule* p_module, const SpvReflectValueData* mother, const SpvReflectTypeDescription* mother_type, uint32_t index, SpvReflectValueData** result, const SpvReflectTypeDescription** child_type) { - if (!(mother_type->type_flags & VECTOR_DISALLOWED_FLAGS)) { - if (!(mother_type->type_flags & SCALAR_DISALLOWED_FLAGS)) { - // scalar types have no composition - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - else { - // mother is a simple vector - SpvReflectTypeDescription* c_type = FindType(p_module, mother_type->component_type_id); - if (!c_type) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; - } - if (index > mother_type->traits.numeric.vector.component_count) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; - } - *child_type = c_type; - if(mother){ - *result = (SpvReflectValueData*)&mother->numeric.vector.value[index]; - } - return SPV_REFLECT_RESULT_SUCCESS; - } + if (!(mother_type->type_flags & VECTOR_DISALLOWED_FLAGS)) { + if (!(mother_type->type_flags & SCALAR_DISALLOWED_FLAGS)) { + // scalar types have no composition + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } else { - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + // mother is a simple vector + SpvReflectTypeDescription* c_type = FindType(p_module, mother_type->component_type_id); + if (!c_type) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; + } + if (index > mother_type->traits.numeric.vector.component_count) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + } + *child_type = c_type; + if(mother){ + *result = (SpvReflectValueData*)&mother->numeric.vector.value[index]; + } + return SPV_REFLECT_RESULT_SUCCESS; } + } + else { + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + } } SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflectValueData* dst, SpvReflectValueData* src) { - if (!(type->type_flags & VECTOR_DISALLOWED_FLAGS)) { - if (!(type->type_flags & SCALAR_DISALLOWED_FLAGS)) { - dst->numeric.scalar = src->numeric.scalar; - // scalar types have no composition - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - else { - dst->numeric.vector = src->numeric.vector; - return SPV_REFLECT_RESULT_SUCCESS; - } + if (!(type->type_flags & VECTOR_DISALLOWED_FLAGS)) { + if (!(type->type_flags & SCALAR_DISALLOWED_FLAGS)) { + dst->numeric.scalar = src->numeric.scalar; + // scalar types have no composition + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; } else { - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + dst->numeric.vector = src->numeric.vector; + return SPV_REFLECT_RESULT_SUCCESS; } -} - -#define CHECK_INSTRUCTION_SIZE(node, expected) \ -{ \ - if (node->word_count != expected) { \ - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; \ - } \ -} - -#define CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_result_node, p_op1_node, res, CLEANUP) \ -{ \ - if ((p_result_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ - if (!((p_op1_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - if ((p_op1_node)->value.type->traits.numeric.vector.component_count != (p_result_node)->value.type->traits.numeric.vector.component_count) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - vec_size = (p_result_node)->value.type->traits.numeric.vector.component_count; \ - } \ -} - -#define CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, p_result_node, p_op1_node, p_op2_node, res, CLEANUP) \ -{ \ - if ((p_result_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ - if (!((p_op1_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - if (!((p_op2_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - if ((p_op1_node)->value.type->traits.numeric.vector.component_count != (p_result_node)->value.type->traits.numeric.vector.component_count) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - if ((p_op2_node)->value.type->traits.numeric.vector.component_count != (p_result_node)->value.type->traits.numeric.vector.component_count) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - vec_size = (p_result_node)->value.type->traits.numeric.vector.component_count; \ - } \ -} - -#define CHECK_WIDTH_MATCH(p_node1, p_node2, res, CLEANUP) \ -{ \ - if ((p_node1)->value.type->traits.numeric.scalar.width != (p_node2)->value.type->traits.numeric.scalar.width) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ -} - -#define CHECK_IS_BASIC_TYPE(p_result_node, b_type, res, CLEANUP) \ -{ \ - if(((p_result_node)->value.type->type_flags & SCALAR_TYPE_FLAGS) != b_type) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ + } + else { + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + } +} + +#define CHECK_INSTRUCTION_SIZE(node, expected) \ +{ \ + if (node->word_count != expected) { \ + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; \ + } \ +} + +#define CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_result_node, p_op1_node, res, CLEANUP) \ +{ \ + if ((p_result_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + if (!((p_op1_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + if ((p_op1_node)->value.type->traits.numeric.vector.component_count != (p_result_node)->value.type->traits.numeric.vector.component_count) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + vec_size = (p_result_node)->value.type->traits.numeric.vector.component_count; \ + } \ +} + +#define CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, p_result_node, p_op1_node, p_op2_node, res, CLEANUP) \ +{ \ + if ((p_result_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + if (!((p_op1_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + if (!((p_op2_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + if ((p_op1_node)->value.type->traits.numeric.vector.component_count != (p_result_node)->value.type->traits.numeric.vector.component_count) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + if ((p_op2_node)->value.type->traits.numeric.vector.component_count != (p_result_node)->value.type->traits.numeric.vector.component_count) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + vec_size = (p_result_node)->value.type->traits.numeric.vector.component_count; \ + } \ +} + +#define CHECK_WIDTH_MATCH(p_node1, p_node2, res, CLEANUP) \ +{ \ + if ((p_node1)->value.type->traits.numeric.scalar.width != (p_node2)->value.type->traits.numeric.scalar.width) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ +} + +#define CHECK_IS_BASIC_TYPE(p_result_node, b_type, res, CLEANUP) \ +{ \ + if(((p_result_node)->value.type->type_flags & SCALAR_TYPE_FLAGS) != b_type) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ } #define CHECK_IS_INTEGER_TYPE(p_result_node, res, CLEANUP) CHECK_IS_BASIC_TYPE(p_result_node, SPV_REFLECT_TYPE_FLAG_INT, res, CLEANUP) @@ -5665,272 +5619,268 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect #define CHECK_IS_BOOLEAN_TYPE(p_result_node, res, CLEANUP) CHECK_IS_BASIC_TYPE(p_result_node, SPV_REFLECT_TYPE_FLAG_BOOL, res, CLEANUP) -#define CHECK_VECTOR_OR_SCALAR_TYPE(p_result_node, res, CLEANUP) \ -{ \ - if ((p_result_node)->value.type && ((p_result_node)->value.type->type_flags & VECTOR_DISALLOWED_FLAGS)) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ +#define CHECK_VECTOR_OR_SCALAR_TYPE(p_result_node, res, CLEANUP) \ +{ \ + if ((p_result_node)->value.type && ((p_result_node)->value.type->type_flags & VECTOR_DISALLOWED_FLAGS)) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ } -#define GET_OPERAND(p_parser, eval, p_node, offset, p_result_node, res, CLEANUP) \ -{ \ - uint32_t operand_id; \ - SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; \ - EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + offset, operand_id, res, CLEANUP); \ - p_result_node = FindEvaluationNode(p_eval, operand_id); \ - if(!p_result_node) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; \ - goto CLEANUP; \ - } \ +#define GET_OPERAND(p_parser, eval, p_node, offset, p_result_node, res, CLEANUP) \ +{ \ + uint32_t operand_id; \ + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; \ + EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + offset, operand_id, res, CLEANUP); \ + p_result_node = FindEvaluationNode(p_eval, operand_id); \ + if(!p_result_node) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; \ + goto CLEANUP; \ + } \ } -#define EVALUATE_OPERAND(p_result_node, res, CLEANUP) \ -{ \ - res = EvaluateResult_Do(p_result_node); \ - if (res != SPV_REFLECT_RESULT_SUCCESS) goto CLEANUP; \ +#define EVALUATE_OPERAND(p_result_node, res, CLEANUP) \ +{ \ + res = EvaluateResult_Do(p_result_node); \ + if (res != SPV_REFLECT_RESULT_SUCCESS) goto CLEANUP; \ } #define SIMPLE_UNARY_OP_32_BIT_HOOK #define SIMPLE_UNARY_OP_64_BIT_HOOK -#define DO_SIMPLE_UNARY_INTEGER_OPERATION(mode, p_simple_op_parser, simple_op_eval, simple_op_node, res, CLEANUP) \ -{ \ - switch (mode) { \ - default: \ - { \ - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; \ - goto CLEANUP; \ - } \ - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: \ - { \ - uint32_t vec_size = 1; \ - if ((simple_op_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ - vec_size = (simple_op_node)->value.type->traits.numeric.vector.component_count; \ - } \ - SpvReflectPrvEvaluationNode* operand1 = (simple_op_node)->id_operands[0]; \ - EVALUATE_OPERAND(operand1, res, CLEANUP) \ - \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value \ - = operand1->value.data.numeric.vector.value[i].undefined_value; \ - switch (operand1->value.type->traits.numeric.scalar.width) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - case 32: \ - /* 32 bit integer */ \ - { \ - int32_t data = operand1->value.data.numeric.vector.value[i].value.sint32_value; \ - SIMPLE_UNARY_OP_32_BIT_HOOK \ - (simple_op_node)->value.data.numeric.vector.value[i].value.sint32_value = data; \ - } \ - break; \ - case 64: \ - /* 64 bit integer */ \ - { \ - int64_t data = operand1->value.data.numeric.vector.value[i].value.sint64_value; \ - SIMPLE_UNARY_OP_64_BIT_HOOK \ - (simple_op_node)->value.data.numeric.vector.value[i].value.sint64_value = data; \ - } \ - break; \ - } \ - } \ - } \ - break; \ - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: \ - { \ - SpvReflectPrvNode* p_parser_node = simple_op_node->instruction_private.uninitialized; \ - CHECK_INSTRUCTION_SIZE(p_parser_node, 5) \ - (simple_op_node)->num_id_operands = 1; \ - (simple_op_node)->num_literal_words = 0; \ - \ - /* check result type */ \ - CHECK_IS_INTEGER_TYPE((simple_op_node), res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node), res, CLEANUP) \ - } \ - break; \ - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: \ - { \ - GET_OPERAND((p_simple_op_parser), (simple_op_eval), (simple_op_node), 4, (simple_op_node)->id_operands[0], res, CLEANUP) \ - CHECK_IS_INTEGER_TYPE((simple_op_node)->id_operands[0], res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node)->id_operands[0], res, CLEANUP) \ - CHECK_WIDTH_MATCH((simple_op_node), (simple_op_node)->id_operands[0], res, CLEANUP) \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, (simple_op_node), (simple_op_node)->id_operands[0], res, CLEANUP) \ - } \ - break; \ - } \ +#define DO_SIMPLE_UNARY_INTEGER_OPERATION(mode, p_simple_op_parser, simple_op_eval, simple_op_node, res, CLEANUP) \ +{ \ + switch (mode) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; \ + goto CLEANUP; \ + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: \ + { \ + uint32_t vec_size = 1; \ + if ((simple_op_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + vec_size = (simple_op_node)->value.type->traits.numeric.vector.component_count; \ + } \ + SpvReflectPrvEvaluationNode* operand1 = (simple_op_node)->id_operands[0]; \ + EVALUATE_OPERAND(operand1, res, CLEANUP) \ + \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value \ + = operand1->value.data.numeric.vector.value[i].undefined_value; \ + switch (operand1->value.type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + /* 32 bit integer */ \ + { \ + int32_t data = operand1->value.data.numeric.vector.value[i].value.sint32_value; \ + SIMPLE_UNARY_OP_32_BIT_HOOK \ + (simple_op_node)->value.data.numeric.vector.value[i].value.sint32_value = data; \ + } \ + break; \ + case 64: \ + /* 64 bit integer */ \ + { \ + int64_t data = operand1->value.data.numeric.vector.value[i].value.sint64_value; \ + SIMPLE_UNARY_OP_64_BIT_HOOK \ + (simple_op_node)->value.data.numeric.vector.value[i].value.sint64_value = data; \ + } \ + break; \ + } \ + } \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: \ + { \ + SpvReflectPrvNode* p_parser_node = simple_op_node->instruction_private.uninitialized; \ + CHECK_INSTRUCTION_SIZE(p_parser_node, 5) \ + (simple_op_node)->num_id_operands = 1; \ + (simple_op_node)->num_literal_words = 0; \ + \ + /* check result type */ \ + CHECK_IS_INTEGER_TYPE((simple_op_node), res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node), res, CLEANUP) \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: \ + { \ + GET_OPERAND((p_simple_op_parser), (simple_op_eval), (simple_op_node), 4, (simple_op_node)->id_operands[0], res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE((simple_op_node)->id_operands[0], res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node)->id_operands[0], res, CLEANUP) \ + CHECK_WIDTH_MATCH((simple_op_node), (simple_op_node)->id_operands[0], res, CLEANUP) \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, (simple_op_node), (simple_op_node)->id_operands[0], res, CLEANUP) \ + } \ + break; \ + } \ } #define SIMPLE_BINARY_OP_32_BIT_HOOK #define SIMPLE_BINARY_OP_64_BIT_HOOK -#define DO_SIMPLE_BINARY_INTEGER_OPERATION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP) \ +#define DO_SIMPLE_BINARY_INTEGER_OPERATION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP) \ +{ \ + switch (mode) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; \ + goto CLEANUP; \ + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: \ + { \ + uint32_t vec_size = 1; \ + if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + vec_size = simple_op_node->value.type->traits.numeric.vector.component_count; \ + } \ + SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0]; \ + SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1]; \ + EVALUATE_OPERAND(operand1, res, CLEANUP) \ + EVALUATE_OPERAND(operand2, res, CLEANUP) \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->value.data.numeric.vector.value[i].undefined_value \ + || operand2->value.data.numeric.vector.value[i].undefined_value) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + switch ((simple_op_node)->value.type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + { \ + /* load data into int32_t*/ \ + int32_t data1 = operand1->value.data.numeric.vector.value[i].value.sint32_value; \ + int32_t data2 = operand2->value.data.numeric.vector.value[i].value.sint32_value; \ + int32_t data = data1 operation data2; \ + SIMPLE_BINARY_OP_32_BIT_HOOK \ + /* write to correct offset */ \ + (simple_op_node)->value.data.numeric.vector.value[i].value.sint32_value = data; \ + } \ + break; \ + case 64: \ + { \ + /* load data into int64_t*/ \ + int64_t data1 = operand1->value.data.numeric.vector.value[i].value.sint64_value; \ + int64_t data2 = operand2->value.data.numeric.vector.value[i].value.sint64_value; \ + int64_t data = data1 operation data2; \ + SIMPLE_BINARY_OP_32_BIT_HOOK \ + /* write to correct offset */ \ + (simple_op_node)->value.data.numeric.vector.value[i].value.sint64_value = data; \ + } \ + break; \ + } \ + } \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: \ + { \ + SpvReflectPrvNode* p_parser_node = simple_op_node->instruction_private.uninitialized; \ + CHECK_INSTRUCTION_SIZE(p_parser_node, 6) \ + simple_op_node->num_id_operands = 2; \ + simple_op_node->num_literal_words = 0; \ + \ + /* check result type */ \ + CHECK_IS_INTEGER_TYPE(simple_op_node, res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node, res, CLEANUP) \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: \ + { \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), simple_op_node, 4, (simple_op_node)->id_operands[0], res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), (simple_op_node), 5, (simple_op_node)->id_operands[1], res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ + \ + /* check agains result */ \ + CHECK_WIDTH_MATCH(simple_op_node, (simple_op_node)->id_operands[0], res, CLEANUP) \ + CHECK_WIDTH_MATCH(simple_op_node, (simple_op_node)->id_operands[1], res, CLEANUP) \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ + } \ + break; \ + } \ +} + +#define DO_UNSIGNED_INTEGER_DIVISION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP) \ { \ - switch (mode) { \ - default: \ - { \ - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; \ - goto CLEANUP; \ - } \ - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: \ - { \ - uint32_t vec_size = 1; \ - if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ - vec_size = simple_op_node->value.type->traits.numeric.vector.component_count; \ + switch (mode) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; \ + goto CLEANUP; \ + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: \ + { \ + uint32_t vec_size = 1; \ + if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + vec_size = simple_op_node->value.type->traits.numeric.vector.component_count; \ + } \ + SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0]; \ + SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1]; \ + EVALUATE_OPERAND(operand1, res, CLEANUP) \ + EVALUATE_OPERAND(operand2, res, CLEANUP) \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->value.data.numeric.vector.value[i].undefined_value \ + || operand2->value.data.numeric.vector.value[i].undefined_value) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + switch ((simple_op_node)->value.type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + { \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value \ + operation operand2->value.data.numeric.vector.value[i].value.uint32_bool_value; \ + if (operand2->value.data.numeric.vector.value[i].value.uint32_bool_value == 0) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ } \ - SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0]; \ - SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1]; \ - EVALUATE_OPERAND(operand1, res, CLEANUP) \ - EVALUATE_OPERAND(operand2, res, CLEANUP) \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1->value.data.numeric.vector.value[i].undefined_value \ - || operand2->value.data.numeric.vector.value[i].undefined_value) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - switch ((simple_op_node)->value.type->traits.numeric.scalar.width) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - case 32: \ - { \ - /* load data into int32_t*/ \ - int32_t data1 = operand1->value.data.numeric.vector.value[i].value.sint32_value; \ - int32_t data2 = operand2->value.data.numeric.vector.value[i].value.sint32_value; \ - int32_t data = data1 operation data2; \ - SIMPLE_BINARY_OP_32_BIT_HOOK \ - /* write to correct offset */ \ - (simple_op_node)->value.data.numeric.vector.value[i].value.sint32_value = data; \ - } \ - break; \ - case 64: \ - { \ - /* load data into int64_t*/ \ - int64_t data1 = operand1->value.data.numeric.vector.value[i].value.sint64_value; \ - int64_t data2 = operand2->value.data.numeric.vector.value[i].value.sint64_value; \ - int64_t data = data1 operation data2; \ - SIMPLE_BINARY_OP_32_BIT_HOOK \ - /* write to correct offset */ \ - (simple_op_node)->value.data.numeric.vector.value[i].value.sint64_value = data; \ - } \ - break; \ - } \ + } \ + break; \ + case 64: \ + { \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint64_value \ + = operand1->value.data.numeric.vector.value[i].value.uint64_value \ + operation operand2->value.data.numeric.vector.value[i].value.uint64_value; \ + if (operand2->value.data.numeric.vector.value[i].value.uint64_value == 0) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ } \ - } \ - break; \ - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: \ - { \ - SpvReflectPrvNode* p_parser_node = simple_op_node->instruction_private.uninitialized; \ - CHECK_INSTRUCTION_SIZE(p_parser_node, 6) \ - simple_op_node->num_id_operands = 2; \ - simple_op_node->num_literal_words = 0; \ - \ - /* check result type */ \ - CHECK_IS_INTEGER_TYPE(simple_op_node, res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node, res, CLEANUP) \ - } \ - break; \ - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: \ - { \ - GET_OPERAND((p_simple_op_parser),(simple_op_eval), simple_op_node, 4, (simple_op_node)->id_operands[0], res, CLEANUP) \ - CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ - GET_OPERAND((p_simple_op_parser),(simple_op_eval), (simple_op_node), 5, (simple_op_node)->id_operands[1], res, CLEANUP) \ - CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ + } \ + break; \ + } \ + } \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: \ + { \ + SpvReflectPrvNode* p_parser_node = simple_op_node->instruction_private.uninitialized; \ + CHECK_INSTRUCTION_SIZE(p_parser_node, 6) \ + (simple_op_node)->num_id_operands = 2; \ + (simple_op_node)->num_literal_words = 0; \ \ - /* check agains result */ \ - CHECK_WIDTH_MATCH(simple_op_node, (simple_op_node)->id_operands[0], res, CLEANUP) \ - CHECK_WIDTH_MATCH(simple_op_node, (simple_op_node)->id_operands[1], res, CLEANUP) \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ - } \ - break; \ - } \ -} - -#define DO_UNSIGNED_INTEGER_DIVISION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP) \ -{ \ - switch (mode) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; \ - goto CLEANUP; \ - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: \ - { \ - uint32_t vec_size = 1; \ - if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ - vec_size = simple_op_node->value.type->traits.numeric.vector.component_count; \ - } \ - SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0]; \ - SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1]; \ - EVALUATE_OPERAND(operand1, res, CLEANUP) \ - EVALUATE_OPERAND(operand2, res, CLEANUP) \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1->value.data.numeric.vector.value[i].undefined_value \ - || operand2->value.data.numeric.vector.value[i].undefined_value) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - switch ((simple_op_node)->value.type->traits.numeric.scalar.width) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - case 32: \ - { \ - (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value \ - operation operand2->value.data.numeric.vector.value[i].value.uint32_bool_value; \ - if (operand2->value.data.numeric.vector.value[i].value.uint32_bool_value == 0) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - } \ - break; \ - case 64: \ - { \ - (simple_op_node)->value.data.numeric.vector.value[i].value.uint64_value \ - = operand1->value.data.numeric.vector.value[i].value.uint64_value \ - operation operand2->value.data.numeric.vector.value[i].value.uint64_value; \ - if (operand2->value.data.numeric.vector.value[i].value.uint64_value == 0) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - } \ - break; \ - } \ - } \ - } \ - break; \ - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: \ - { \ - SpvReflectPrvNode* p_parser_node = simple_op_node->instruction_private.uninitialized; \ - CHECK_INSTRUCTION_SIZE(p_parser_node, 6) \ - (simple_op_node)->num_id_operands = 2; \ - (simple_op_node)->num_literal_words = 0; \ - \ - /* check result type */ \ - CHECK_IS_INTEGER_TYPE((simple_op_node), res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node), res, CLEANUP) \ - if ((simple_op_node)->value.type->traits.numeric.scalar.signedness) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - } \ - break; \ - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: \ - { \ - GET_OPERAND((p_simple_op_parser),(simple_op_eval), simple_op_node, 4, simple_op_node->id_operands[0], res, CLEANUP) \ - if((simple_op_node)->id_operands[0]->value.type->id != (simple_op_node)->value.type->id) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - GET_OPERAND((p_simple_op_parser),(simple_op_eval), simple_op_node, 5, simple_op_node->id_operands[1], res, CLEANUP) \ - if((simple_op_node)->id_operands[1]->value.type->id != (simple_op_node)->value.type->id) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (simple_op_node), (simple_op_node)->id_operands[0], (simple_op_node)->id_operands[1], res, CLEANUP) \ - } \ - break; \ - } \ + /* check result type */ \ + CHECK_IS_INTEGER_TYPE((simple_op_node), res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node), res, CLEANUP) \ + if ((simple_op_node)->value.type->traits.numeric.scalar.signedness) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: \ + { \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), simple_op_node, 4, simple_op_node->id_operands[0], res, CLEANUP) \ + if((simple_op_node)->id_operands[0]->value.type->id != (simple_op_node)->value.type->id) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), simple_op_node, 5, simple_op_node->id_operands[1], res, CLEANUP) \ + if((simple_op_node)->id_operands[1]->value.type->id != (simple_op_node)->value.type->id) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (simple_op_node), (simple_op_node)->id_operands[0], (simple_op_node)->id_operands[1], res, CLEANUP) \ + } \ + break; \ + } \ } #define SHIFT_OP_32_BIT_HOOK_PRE @@ -5938,238 +5888,238 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect #define SHIFT_OP_32_BIT_HOOK_POST #define SHIFT_OP_64_BIT_HOOK_POST -#define DO_SHIFT_OPERATION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP) \ -{ \ - switch (mode) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; \ - goto CLEANUP; \ - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: \ - { \ - uint32_t vec_size = 1; \ - if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ - vec_size = simple_op_node->value.type->traits.numeric.vector.component_count; \ - } \ - SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0]; \ - SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1]; \ - EVALUATE_OPERAND(operand1, res, CLEANUP) \ - EVALUATE_OPERAND(operand2, res, CLEANUP) \ - uint32_t res_width = ((simple_op_node))->value.type->traits.numeric.scalar.width; \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1->value.data.numeric.vector.value[i].undefined_value \ - || operand2->value.data.numeric.vector.value[i].undefined_value) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - /* load the shift number, set undefined flag if larger than result width*/ \ - uint8_t shift_num; \ - switch (operand2->value.type->traits.numeric.scalar.width) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - case 32: \ - { \ - uint32_t shift = operand2->value.data.numeric.vector.value[i].value.uint32_bool_value; \ - if (operand1->value.data.numeric.vector.value[i].undefined_value || shift >= res_width) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - shift_num = (uint8_t)shift; \ - } \ - break; \ - case 64: \ - { \ - uint64_t shift = operand2->value.data.numeric.vector.value[i].value.uint64_value; \ - if (operand1->value.data.numeric.vector.value[i].undefined_value || shift >= res_width) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - shift_num = (uint8_t)shift; \ - } \ - break; \ - } \ - switch (res_width) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - case 32: \ - { \ - uint32_t data = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value; \ - SHIFT_OP_32_BIT_HOOK_PRE \ - data operation##= shift_num; \ - SHIFT_OP_32_BIT_HOOK_POST \ - (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value = data; \ - } \ - break; \ - case 64: \ - { \ - uint64_t data = operand1->value.data.numeric.vector.value[i].value.uint64_value; \ - SHIFT_OP_64_BIT_HOOK_PRE \ - data operation##= shift_num; \ - SHIFT_OP_64_BIT_HOOK_POST \ - (simple_op_node)->value.data.numeric.vector.value[i].value.uint64_value = data; \ - } \ - break; \ - } \ - } \ - } \ - break; \ - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: \ - { \ - SpvReflectPrvNode* p_parser_node = simple_op_node->instruction_private.uninitialized; \ - CHECK_INSTRUCTION_SIZE(p_parser_node, 6) \ - simple_op_node->num_id_operands = 2; \ - simple_op_node->num_literal_words = 0; \ - \ - /* check result type */ \ - CHECK_IS_INTEGER_TYPE(simple_op_node, res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node, res, CLEANUP) \ - } \ - break; \ - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: \ - { \ - GET_OPERAND((p_simple_op_parser),(simple_op_eval), simple_op_node, 4, (simple_op_node)->id_operands[0], res, CLEANUP) \ - CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ - GET_OPERAND((p_simple_op_parser),(simple_op_eval), (simple_op_node), 5, (simple_op_node)->id_operands[1], res, CLEANUP) \ - CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ - \ - /* op1 and result must have same width */ \ - CHECK_WIDTH_MATCH(simple_op_node, (simple_op_node)->id_operands[0], res, CLEANUP) \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ - } \ - break; \ - } \ -} - -#define DO_BINARY_BOOLEAN_LOGICAL_OPERATION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP) \ -{ \ - switch (mode) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; \ - goto CLEANUP; \ - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: \ - { \ - uint32_t vec_size = 1; \ - if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ - vec_size = simple_op_node->value.type->traits.numeric.vector.component_count; \ - } \ - SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0]; \ - SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1]; \ - EVALUATE_OPERAND(operand1, res, CLEANUP) \ - EVALUATE_OPERAND(operand2, res, CLEANUP) \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1->value.data.numeric.vector.value[i].undefined_value \ - operation operand2->value.data.numeric.vector.value[i].undefined_value) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - /* write to correct offset */ \ - (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value \ - operation operand2->value.data.numeric.vector.value[i].value.uint32_bool_value; \ - } \ - } \ - break; \ - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: \ - { \ - SpvReflectPrvNode* p_parser_node = simple_op_node->instruction_private.uninitialized; \ - CHECK_INSTRUCTION_SIZE(p_parser_node, 6) \ - simple_op_node->num_id_operands = 2; \ - simple_op_node->num_literal_words = 0; \ - \ - /* check result type */ \ - CHECK_IS_BOOLEAN_TYPE((simple_op_node), res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node), res, CLEANUP) \ - if ((simple_op_node)->value.type->traits.numeric.scalar.signedness) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - } \ - break; \ - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: \ - { \ - GET_OPERAND((p_simple_op_parser),(simple_op_eval), simple_op_node, 4, (simple_op_node)->id_operands[0], res, CLEANUP) \ - CHECK_IS_BOOLEAN_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ - GET_OPERAND((p_simple_op_parser),(simple_op_eval), (simple_op_node), 5, (simple_op_node)->id_operands[1], res, CLEANUP) \ - CHECK_IS_BOOLEAN_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ - \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ - } \ - break; \ - } \ -} - -#define DO_BINARY_INTEGER_LOGICAL_OPERATION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, _32bit_member, _64bit_member, res, CLEANUP) \ -{ \ - switch (mode) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; \ - goto CLEANUP; \ - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: \ - { \ - uint32_t vec_size = 1; \ - if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ - vec_size = simple_op_node->value.type->traits.numeric.vector.component_count; \ - } \ - SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0]; \ - SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1]; \ - EVALUATE_OPERAND(operand1, res, CLEANUP) \ - EVALUATE_OPERAND(operand2, res, CLEANUP) \ - for (uint32_t i = 0; i < vec_size; ++i) { \ - if (operand1->value.data.numeric.vector.value[i].undefined_value \ - || operand2->value.data.numeric.vector.value[i].undefined_value) { \ - (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - switch (operand1->value.type->traits.numeric.scalar.width) { \ - default: \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - case 32: \ - (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1->value.data.numeric.vector.value[i].value.##_32bit_member \ - operation operand2->value.data.numeric.vector.value[i].value.##_32bit_member; \ - break; \ - case 64: \ - (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1->value.data.numeric.vector.value[i].value.##_64bit_member \ - operation operand2->value.data.numeric.vector.value[i].value.##_64bit_member; \ - break; \ - } \ - } \ - } \ - break; \ - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: \ - { \ - SpvReflectPrvNode* p_parser_node = simple_op_node->instruction_private.uninitialized; \ - CHECK_INSTRUCTION_SIZE(p_parser_node, 6) \ - simple_op_node->num_id_operands = 2; \ - simple_op_node->num_literal_words = 0; \ - \ - /* check result type */ \ - CHECK_IS_BOOLEAN_TYPE((simple_op_node), res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node), res, CLEANUP) \ - if ((simple_op_node)->value.type->traits.numeric.scalar.signedness) { \ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ - goto CLEANUP; \ - } \ - } \ - break; \ - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: \ - { \ - GET_OPERAND((p_simple_op_parser),(simple_op_eval), simple_op_node, 4, (simple_op_node)->id_operands[0], res, CLEANUP) \ - CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ - GET_OPERAND((p_simple_op_parser),(simple_op_eval), (simple_op_node), 5, (simple_op_node)->id_operands[1], res, CLEANUP) \ - CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ - CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ - \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ - } \ - break; \ - } \ +#define DO_SHIFT_OPERATION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP) \ +{ \ + switch (mode) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; \ + goto CLEANUP; \ + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: \ + { \ + uint32_t vec_size = 1; \ + if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + vec_size = simple_op_node->value.type->traits.numeric.vector.component_count; \ + } \ + SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0]; \ + SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1]; \ + EVALUATE_OPERAND(operand1, res, CLEANUP) \ + EVALUATE_OPERAND(operand2, res, CLEANUP) \ + uint32_t res_width = ((simple_op_node))->value.type->traits.numeric.scalar.width; \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->value.data.numeric.vector.value[i].undefined_value \ + || operand2->value.data.numeric.vector.value[i].undefined_value) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + /* load the shift number, set undefined flag if larger than result width*/ \ + uint8_t shift_num; \ + switch (operand2->value.type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + { \ + uint32_t shift = operand2->value.data.numeric.vector.value[i].value.uint32_bool_value; \ + if (operand1->value.data.numeric.vector.value[i].undefined_value || shift >= res_width) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + shift_num = (uint8_t)shift; \ + } \ + break; \ + case 64: \ + { \ + uint64_t shift = operand2->value.data.numeric.vector.value[i].value.uint64_value; \ + if (operand1->value.data.numeric.vector.value[i].undefined_value || shift >= res_width) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + shift_num = (uint8_t)shift; \ + } \ + break; \ + } \ + switch (res_width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + { \ + uint32_t data = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value; \ + SHIFT_OP_32_BIT_HOOK_PRE \ + data operation##= shift_num; \ + SHIFT_OP_32_BIT_HOOK_POST \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value = data; \ + } \ + break; \ + case 64: \ + { \ + uint64_t data = operand1->value.data.numeric.vector.value[i].value.uint64_value; \ + SHIFT_OP_64_BIT_HOOK_PRE \ + data operation##= shift_num; \ + SHIFT_OP_64_BIT_HOOK_POST \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint64_value = data; \ + } \ + break; \ + } \ + } \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: \ + { \ + SpvReflectPrvNode* p_parser_node = simple_op_node->instruction_private.uninitialized; \ + CHECK_INSTRUCTION_SIZE(p_parser_node, 6) \ + simple_op_node->num_id_operands = 2; \ + simple_op_node->num_literal_words = 0; \ + \ + /* check result type */ \ + CHECK_IS_INTEGER_TYPE(simple_op_node, res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node, res, CLEANUP) \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: \ + { \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), simple_op_node, 4, (simple_op_node)->id_operands[0], res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), (simple_op_node), 5, (simple_op_node)->id_operands[1], res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ + \ + /* op1 and result must have same width */ \ + CHECK_WIDTH_MATCH(simple_op_node, (simple_op_node)->id_operands[0], res, CLEANUP) \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ + } \ + break; \ + } \ +} + +#define DO_BINARY_BOOLEAN_LOGICAL_OPERATION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP) \ +{ \ + switch (mode) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; \ + goto CLEANUP; \ + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: \ + { \ + uint32_t vec_size = 1; \ + if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + vec_size = simple_op_node->value.type->traits.numeric.vector.component_count; \ + } \ + SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0]; \ + SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1]; \ + EVALUATE_OPERAND(operand1, res, CLEANUP) \ + EVALUATE_OPERAND(operand2, res, CLEANUP) \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->value.data.numeric.vector.value[i].undefined_value \ + operation operand2->value.data.numeric.vector.value[i].undefined_value) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + /* write to correct offset */ \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value \ + operation operand2->value.data.numeric.vector.value[i].value.uint32_bool_value; \ + } \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: \ + { \ + SpvReflectPrvNode* p_parser_node = simple_op_node->instruction_private.uninitialized; \ + CHECK_INSTRUCTION_SIZE(p_parser_node, 6) \ + simple_op_node->num_id_operands = 2; \ + simple_op_node->num_literal_words = 0; \ + \ + /* check result type */ \ + CHECK_IS_BOOLEAN_TYPE((simple_op_node), res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node), res, CLEANUP) \ + if ((simple_op_node)->value.type->traits.numeric.scalar.signedness) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: \ + { \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), simple_op_node, 4, (simple_op_node)->id_operands[0], res, CLEANUP) \ + CHECK_IS_BOOLEAN_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), (simple_op_node), 5, (simple_op_node)->id_operands[1], res, CLEANUP) \ + CHECK_IS_BOOLEAN_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ + \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ + } \ + break; \ + } \ +} + +#define DO_BINARY_INTEGER_LOGICAL_OPERATION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, _32bit_member, _64bit_member, res, CLEANUP) \ +{ \ + switch (mode) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; \ + goto CLEANUP; \ + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: \ + { \ + uint32_t vec_size = 1; \ + if (simple_op_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ + vec_size = simple_op_node->value.type->traits.numeric.vector.component_count; \ + } \ + SpvReflectPrvEvaluationNode* operand1 = simple_op_node->id_operands[0]; \ + SpvReflectPrvEvaluationNode* operand2 = simple_op_node->id_operands[1]; \ + EVALUATE_OPERAND(operand1, res, CLEANUP) \ + EVALUATE_OPERAND(operand2, res, CLEANUP) \ + for (uint32_t i = 0; i < vec_size; ++i) { \ + if (operand1->value.data.numeric.vector.value[i].undefined_value \ + || operand2->value.data.numeric.vector.value[i].undefined_value) { \ + (simple_op_node)->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + switch (operand1->value.type->traits.numeric.scalar.width) { \ + default: \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + case 32: \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1->value.data.numeric.vector.value[i].value.##_32bit_member \ + operation operand2->value.data.numeric.vector.value[i].value.##_32bit_member; \ + break; \ + case 64: \ + (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ + = operand1->value.data.numeric.vector.value[i].value.##_64bit_member \ + operation operand2->value.data.numeric.vector.value[i].value.##_64bit_member; \ + break; \ + } \ + } \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: \ + { \ + SpvReflectPrvNode* p_parser_node = simple_op_node->instruction_private.uninitialized; \ + CHECK_INSTRUCTION_SIZE(p_parser_node, 6) \ + simple_op_node->num_id_operands = 2; \ + simple_op_node->num_literal_words = 0; \ + \ + /* check result type */ \ + CHECK_IS_BOOLEAN_TYPE((simple_op_node), res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node), res, CLEANUP) \ + if ((simple_op_node)->value.type->traits.numeric.scalar.signedness) { \ + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ + goto CLEANUP; \ + } \ + } \ + break; \ + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: \ + { \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), simple_op_node, 4, (simple_op_node)->id_operands[0], res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[0], res, CLEANUP) \ + GET_OPERAND((p_simple_op_parser),(simple_op_eval), (simple_op_node), 5, (simple_op_node)->id_operands[1], res, CLEANUP) \ + CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ + CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ + \ + uint32_t vec_size = 1; \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ + } \ + break; \ + } \ } #define DO_BINARY_UINTEGER_LOGICAL_OPERATION(mode, p_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP) \ @@ -6184,1173 +6134,1163 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect // remove the inner branches... static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node, SpvReflectEvaluationMode evaluation_mode, SpvReflectPrvParser* p_parser) { - if (!p_node) return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + if (!p_node) return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + + SpvReflectResult res = SPV_REFLECT_RESULT_SUCCESS; + switch (evaluation_mode) { + default: + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED; + return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + switch (p_node->evaluation_state) { + case SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED: + return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + case SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED: + return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + case SPV_REFLECT_EVALUATION_NODE_STATE_PENDING: + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_WORKING; + break; + case SPV_REFLECT_EVALUATION_NODE_STATE_WORKING: + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_FAILED; + return SPV_REFLECT_RESULT_ERROR_SPIRV_RECURSION; + case SPV_REFLECT_EVALUATION_NODE_STATE_DONE: + return SPV_REFLECT_RESULT_SUCCESS; + case SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED: + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_WORKING; + break; + case SPV_REFLECT_EVALUATION_NODE_STATE_FAILED: + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + switch (p_node->evaluation_state) { + case SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED: + break; + case SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED: + return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + case SPV_REFLECT_EVALUATION_NODE_STATE_PENDING: + case SPV_REFLECT_EVALUATION_NODE_STATE_WORKING: + case SPV_REFLECT_EVALUATION_NODE_STATE_DONE: + case SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED: + case SPV_REFLECT_EVALUATION_NODE_STATE_FAILED: + return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { + switch (p_node->evaluation_state) { + case SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED: + break; + case SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED: + return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + case SPV_REFLECT_EVALUATION_NODE_STATE_PENDING: + case SPV_REFLECT_EVALUATION_NODE_STATE_WORKING: + case SPV_REFLECT_EVALUATION_NODE_STATE_DONE: + case SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED: + case SPV_REFLECT_EVALUATION_NODE_STATE_FAILED: + return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + } + } + break; + } - SpvReflectResult res = SPV_REFLECT_RESULT_SUCCESS; - switch (evaluation_mode) { + SpvReflectValue* result = &p_node->value; + if (!result->type) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; + } + + switch (p_node->op) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + break; + case SpvOpConstantTrue: case SpvOpConstantFalse: + case SpvOpConstant: + case SpvOpSpecConstantTrue: case SpvOpSpecConstantFalse: + case SpvOpSpecConstant: + switch (evaluation_mode) { default: - p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED; - return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + { + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + } case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + p_node->num_id_operands = 0; + p_node->num_literal_words = 0; + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + break; + } + break; + case SpvOpSpecConstantComposite: + { + // only support compositing vector types for now... + // vectors are needed for spv compiled to WorkgroupSize builtin + // in expressing actual localsize + if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + goto CLEANUP; + } + switch (evaluation_mode) { + default: { - switch(p_node->evaluation_state){ - case SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED: - return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; - case SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED: - return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; - case SPV_REFLECT_EVALUATION_NODE_STATE_PENDING: - p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_WORKING; - break; - case SPV_REFLECT_EVALUATION_NODE_STATE_WORKING: - p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_FAILED; - return SPV_REFLECT_RESULT_ERROR_SPIRV_RECURSION; - case SPV_REFLECT_EVALUATION_NODE_STATE_DONE: - return SPV_REFLECT_RESULT_SUCCESS; - case SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED: - p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_WORKING; - break; - case SPV_REFLECT_EVALUATION_NODE_STATE_FAILED: - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; - } + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + } + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + for (uint32_t i = 0; i < p_node->num_id_operands; ++i) { + result->data.numeric.vector.value[i] = p_node->id_operands[i]->value.data.numeric.scalar; + } } break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: { - switch (p_node->evaluation_state) { - case SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED: - break; - case SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED: - return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; - case SPV_REFLECT_EVALUATION_NODE_STATE_PENDING: - case SPV_REFLECT_EVALUATION_NODE_STATE_WORKING: - case SPV_REFLECT_EVALUATION_NODE_STATE_DONE: - case SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED: - case SPV_REFLECT_EVALUATION_NODE_STATE_FAILED: - return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; - } + p_node->num_literal_words = 0; + uint32_t vec_size = 1; + // should always have, since scalars do not need composite + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + vec_size = result->type->traits.numeric.vector.component_count; + } + // other types here? + if (vec_size == 1) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + // check instruction size + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + if (p_parser_node->word_count != 3 + vec_size) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + goto CLEANUP; + } + p_node->num_id_operands = vec_size; } break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: { - switch (p_node->evaluation_state) { - case SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED: - break; - case SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED: - return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; - case SPV_REFLECT_EVALUATION_NODE_STATE_PENDING: - case SPV_REFLECT_EVALUATION_NODE_STATE_WORKING: - case SPV_REFLECT_EVALUATION_NODE_STATE_DONE: - case SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED: - case SPV_REFLECT_EVALUATION_NODE_STATE_FAILED: - return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + for (uint32_t i = 0; i < p_node->num_id_operands; ++i) { + GET_OPERAND(p_parser, p_eval, p_node, 3 + i, p_node->id_operands[i], res, CLEANUP) + // check type compatibility + if (p_node->id_operands[i]->value.type->id != p_node->value.type->component_type_id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } + } } break; - } - - SpvReflectValue* result = &p_node->value; - if (!result->type) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; - } + } + } + break; + case SpvOpSpecConstantOp: + { + // operation has result type id, thus must be typed + + // only vector and scalar types of int/bool/float types implemented + // only OpSelect, OpUndef and access chain instructions can work with non-vector or scalar types + // they are not currently supported... (likely never will) + if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + goto CLEANUP; + } + if (evaluation_mode == SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS) { + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 3, p_node->specOp, res, CLEANUP); + } - switch (p_node->op) { - default: + switch (p_node->specOp) { + default: res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; - break; - case SpvOpConstantTrue: case SpvOpConstantFalse: - case SpvOpConstant: - case SpvOpSpecConstantTrue: case SpvOpSpecConstantFalse: - case SpvOpSpecConstant: - switch (evaluation_mode) { + goto CLEANUP; + case SpvOpUndef: + // write undefined value to result... + { + switch (evaluation_mode) { default: - { - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; - goto CLEANUP; - } + { + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + } case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: - break; + { + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + for (uint32_t i = 0; i < result->type->traits.numeric.vector.component_count; ++i) { + result->data.numeric.vector.value[i].undefined_value = 1; + } + } + else { + result->data.numeric.scalar.undefined_value = 1; + } + } + break; case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: - { - p_node->num_id_operands = 0; - p_node->num_literal_words = 0; + { + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + CHECK_INSTRUCTION_SIZE(p_parser_node, 4) + p_node->num_id_operands = 0; + p_node->num_literal_words = 0; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VOID) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } - break; + } + break; case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: - break; + break; + } } break; - case SpvOpSpecConstantComposite: + case SpvOpSConvert: + // sign extend or truncate integers. + // result is scalar or vector integer type. + // vectors should be of same length { - // only support compositing vector types for now... - // vectors are needed for spv compiled to WorkgroupSize builtin - // in expressing actual localsize - if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; - goto CLEANUP; - } - switch (evaluation_mode) { - default: - { - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; - goto CLEANUP; - } - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: - { - for (uint32_t i = 0; i < p_node->num_id_operands; ++i) { - result->data.numeric.vector.value[i] = p_node->id_operands[i]->value.data.numeric.scalar; - } - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: - { - p_node->num_literal_words = 0; - uint32_t vec_size = 1; - // should always have, since scalars do not need composite - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - vec_size = result->type->traits.numeric.vector.component_count; + switch (evaluation_mode) { + default: + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + vec_size = result->type->traits.numeric.vector.component_count; + } + SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; + EVALUATE_OPERAND(operand1, res, CLEANUP) + for (uint32_t i = 0; i < vec_size; ++i) { + result->data.numeric.vector.value[i].undefined_value = operand1->value.data.numeric.vector.value[i].undefined_value; + switch (operand1->value.type->traits.numeric.scalar.width) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + case 32: + { + int32_t data = operand1->value.data.numeric.vector.value[i].value.sint32_value; + switch (result->type->traits.numeric.scalar.width) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + case 32: + result->data.numeric.vector.value[i].value.sint32_value = data; + break; + case 64: + result->data.numeric.vector.value[i].value.sint64_value = (int64_t)data; + break; } - // other types here? - if (vec_size == 1) { + } + break; + case 64: + { + int64_t data = operand1->value.data.numeric.vector.value[i].value.sint64_value; + switch (result->type->traits.numeric.scalar.width) { + default: res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + case 32: + result->data.numeric.vector.value[i].value.sint32_value = (int32_t)data; + break; + case 64: + result->data.numeric.vector.value[i].value.sint64_value = data; + break; } - // check instruction size - SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; - if (p_parser_node->word_count != 3 + vec_size) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + } + break; + } + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + CHECK_INSTRUCTION_SIZE(p_parser_node, 5) + p_node->num_id_operands = 1; + p_node->num_literal_words = 0; + + // check result type + CHECK_IS_INTEGER_TYPE(p_node, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { + GET_OPERAND(p_parser, p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) + CHECK_IS_INTEGER_TYPE(p_node->id_operands[0], res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) + + // operand must be signed + if (!p_node->id_operands[0]->value.type->traits.numeric.scalar.signedness) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + uint32_t vec_size = 1; + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_node, p_node->id_operands[0], res, CLEANUP) + } + break; + } + } + break; + case SpvOpUConvert: + // zero extend or truncate integers. + // result is scalar or vector integer type. + // vectors should be of same length + { + switch (evaluation_mode) { + default: + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + vec_size = result->type->traits.numeric.vector.component_count; + } + SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; + EVALUATE_OPERAND(operand1, res, CLEANUP) + for (uint32_t i = 0; i < vec_size; ++i) { + result->data.numeric.vector.value[i].undefined_value = operand1->value.data.numeric.vector.value[i].undefined_value; + switch (operand1->value.type->traits.numeric.scalar.width) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + case 32: + { + uint32_t data = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value; + switch (result->type->traits.numeric.scalar.width) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; + case 32: + result->data.numeric.vector.value[i].value.uint32_bool_value = data; + break; + case 64: + result->data.numeric.vector.value[i].value.uint64_value = (uint64_t)data; + break; } - p_node->num_id_operands = vec_size; - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: - { - for (uint32_t i = 0; i < p_node->num_id_operands; ++i) { - GET_OPERAND(p_parser, p_eval, p_node, 3 + i, p_node->id_operands[i], res, CLEANUP) - // check type compatibility - if (p_node->id_operands[i]->value.type->id != p_node->value.type->component_type_id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } + } + break; + case 64: + { + uint64_t data = operand1->value.data.numeric.vector.value[i].value.uint64_value; + switch (result->type->traits.numeric.scalar.width) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + case 32: + result->data.numeric.vector.value[i].value.uint32_bool_value = (uint32_t)data; + break; + case 64: + result->data.numeric.vector.value[i].value.uint64_value = data; + break; } + } + break; + } + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + CHECK_INSTRUCTION_SIZE(p_parser_node, 5) + p_node->num_id_operands = 1; + p_node->num_literal_words = 0; + + // check result type + CHECK_IS_INTEGER_TYPE(p_node, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { + GET_OPERAND(p_parser, p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) + CHECK_IS_INTEGER_TYPE(p_node->id_operands[0], res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) + + // operand must be unsigned + if (p_node->id_operands[0]->value.type->traits.numeric.scalar.signedness) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + uint32_t vec_size = 1; + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_node, p_node->id_operands[0], res, CLEANUP) + } + break; + } + } + break; + case SpvOpFConvert: + // convert of floating point integer to any integer of different width. + // just 32 and 64 bit for now... + { + switch (evaluation_mode) { + default: + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + uint32_t vec_size = 1; + if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + vec_size = result->type->traits.numeric.vector.component_count; + } + SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; + EVALUATE_OPERAND(operand1, res, CLEANUP) + // now do the job + for (uint32_t i = 0; i < vec_size; ++i) { + result->data.numeric.vector.value[i].undefined_value = operand1->value.data.numeric.vector.value[i].undefined_value; + switch (operand1->value.type->traits.numeric.scalar.width) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + case 32: + // convert int32 to generic integer type + switch (result->type->traits.numeric.scalar.width) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + case 32: + result->data.numeric.vector.value[i].value.float32_value = operand1->value.data.numeric.vector.value[i].value.float32_value; + break; + case 64: + result->data.numeric.vector.value[i].value.float64_value = (double)operand1->value.data.numeric.vector.value[i].value.float32_value; + break; + } + break; + case 64: + // convert int64 to generic integer type + switch (result->type->traits.numeric.scalar.width) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + case 32: + result->data.numeric.vector.value[i].value.float32_value = (float)operand1->value.data.numeric.vector.value[i].value.float64_value; + break; + case 64: + result->data.numeric.vector.value[i].value.float64_value = operand1->value.data.numeric.vector.value[i].value.float64_value; + break; + } + } + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + CHECK_INSTRUCTION_SIZE(p_parser_node, 5) + p_node->num_id_operands = 1; + p_node->num_literal_words = 0; + + // check result type + CHECK_IS_FLOAT_TYPE(p_node, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { + GET_OPERAND(p_parser, p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) + CHECK_IS_FLOAT_TYPE(p_node->id_operands[0], res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) + + // vector size must match + uint32_t vec_size = 1; + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_node, p_node->id_operands[0], res, CLEANUP) + } + break; + } + } + break; + case SpvOpSNegate: + #undef SIMPLE_UNARY_OP_32_BIT_HOOK + #undef SIMPLE_UNARY_OP_64_BIT_HOOK + #define SIMPLE_UNARY_OP_32_BIT_HOOK {data = -data;} + #define SIMPLE_UNARY_OP_64_BIT_HOOK {data = -data;} + DO_SIMPLE_UNARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, res, CLEANUP) + #undef SIMPLE_UNARY_OP_32_BIT_HOOK + #undef SIMPLE_UNARY_OP_64_BIT_HOOK + #define SIMPLE_UNARY_OP_32_BIT_HOOK + #define SIMPLE_UNARY_OP_64_BIT_HOOK + break; + case SpvOpNot: + // bitwise not of every component in op1, store into same width result. + #undef SIMPLE_UNARY_OP_32_BIT_HOOK + #undef SIMPLE_UNARY_OP_64_BIT_HOOK + #define SIMPLE_UNARY_OP_32_BIT_HOOK data ^= 0xffffffff; + #define SIMPLE_UNARY_OP_64_BIT_HOOK data ^= 0xffffffffffffffff; + DO_SIMPLE_UNARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, res, CLEANUP) + #undef SIMPLE_UNARY_OP_32_BIT_HOOK + #undef SIMPLE_UNARY_OP_64_BIT_HOOK + #define SIMPLE_UNARY_OP_32_BIT_HOOK + #define SIMPLE_UNARY_OP_64_BIT_HOOK + break; + case SpvOpIAdd: + // integer add. + // subtraction result is the same for 2-compliment + DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, +, res, CLEANUP) + break; + case SpvOpISub: + // integer subtract. + // subtraction result is the same for 2-compliment + DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, -, res, CLEANUP) + break; + case SpvOpIMul: + // integer multiply... + // imul instruction on x86, signed and unsigned have no difference in result + // except for how they overflow. + DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, *, res, CLEANUP) + break; + case SpvOpUDiv: + // unsigned divide + // All operand must be same unsigned integer scalar or vector type. + // x86 div instruction + // emits undefined value if divide by zero + DO_UNSIGNED_INTEGER_DIVISION(evaluation_mode, p_parser, p_eval, p_node, / , res, CLEANUP) + break; + case SpvOpSDiv: + // signed divide + // x86 idiv instruction + // same bits, same vector size, no sign requirements. + // accessing result types that are not signed violates strict aliasing rules. + // emits undefined value if divide by zero or 0x80000... divides -1 + #undef SIMPLE_BINARY_OP_32_BIT_HOOK + #define SIMPLE_BINARY_OP_32_BIT_HOOK \ + if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ + p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ + } + #undef SIMPLE_BINARY_OP_64_BIT_HOOK + #define SIMPLE_BINARY_OP_64_BIT_HOOK \ + if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ + p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ + } + DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, / , res, CLEANUP) + #undef SIMPLE_BINARY_OP_32_BIT_HOOK + #undef SIMPLE_BINARY_OP_64_BIT_HOOK + #define SIMPLE_BINARY_OP_32_BIT_HOOK + #define SIMPLE_BINARY_OP_64_BIT_HOOK + break; + case SpvOpUMod: + // unsigned modulo + // all types must be same unsigned integer scalar or vector type. + DO_UNSIGNED_INTEGER_DIVISION(evaluation_mode, p_parser, p_eval, p_node, %, res, CLEANUP) + break; + case SpvOpSRem: + // just the result of % operator. + #undef SIMPLE_BINARY_OP_32_BIT_HOOK + #define SIMPLE_BINARY_OP_32_BIT_HOOK \ + if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ + p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ + } + #undef SIMPLE_BINARY_OP_64_BIT_HOOK + #define SIMPLE_BINARY_OP_64_BIT_HOOK \ + if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ + p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ + } + DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, %, res, CLEANUP) + #undef SIMPLE_BINARY_OP_32_BIT_HOOK + #undef SIMPLE_BINARY_OP_64_BIT_HOOK + #define SIMPLE_BINARY_OP_32_BIT_HOOK + #define SIMPLE_BINARY_OP_64_BIT_HOOK + break; + case SpvOpSMod: + // not result of % operator, need adjusting with dividend... + #undef SIMPLE_BINARY_OP_32_BIT_HOOK + #define SIMPLE_BINARY_OP_32_BIT_HOOK \ + if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ + p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + else if (data != 0) { \ + int sign1 = 0, sign2 = 0; \ + if (data < 0) sign1 = 1; \ + if (data2 < 0) sign2 = 1; \ + /* remainder is not same as modulo here...*/ \ + if ((sign1 + sign2) == 1) { \ + data += data2; \ + } \ + } + #undef SIMPLE_BINARY_OP_64_BIT_HOOK + #define SIMPLE_BINARY_OP_64_BIT_HOOK \ + if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ + p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ + } \ + else if (data != 0) { \ + int sign1 = 0, sign2 = 0; \ + if (data < 0) sign1 = 1; \ + if (data2 < 0) sign2 = 1; \ + /* remainder is not same as modulo here...*/ \ + if ((sign1 + sign2) == 1) { \ + data += data2; \ + } \ + } + DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, %, res, CLEANUP) + #undef SIMPLE_BINARY_OP_32_BIT_HOOK + #undef SIMPLE_BINARY_OP_64_BIT_HOOK + #define SIMPLE_BINARY_OP_32_BIT_HOOK + #define SIMPLE_BINARY_OP_64_BIT_HOOK + break; + case SpvOpShiftRightLogical: + // zero fill right shift. Just >> in c + DO_SHIFT_OPERATION(evaluation_mode, p_parser, p_eval, p_node, >> , res, CLEANUP) + break; + case SpvOpShiftRightArithmetic: + // fill with sign of original number. + #undef SHIFT_OP_32_BIT_HOOK_PRE + #undef SHIFT_OP_64_BIT_HOOK_PRE + #undef SHIFT_OP_32_BIT_HOOK_POST + #undef SHIFT_OP_64_BIT_HOOK_POST + #define SHIFT_OP_32_BIT_HOOK_PRE uint32_t sign_bit = data & 0x80000000; + #define SHIFT_OP_64_BIT_HOOK_PRE uint64_t sign_bit = data & 0x8000000000000000; + #define SHIFT_OP_32_BIT_HOOK_POST \ + if (sign_bit) { \ + uint32_t fill = 0xffffffff << (32 - shift_num); \ + data |= fill; \ + } + #define SHIFT_OP_64_BIT_HOOK_POST \ + if (sign_bit) { \ + uint64_t fill = 0xffffffffffffffff << (64 - shift_num); \ + data |= fill; \ + } + DO_SHIFT_OPERATION(evaluation_mode, p_parser, p_eval, p_node, >> , res, CLEANUP) + #undef SHIFT_OP_32_BIT_HOOK_PRE + #undef SHIFT_OP_64_BIT_HOOK_PRE + #undef SHIFT_OP_32_BIT_HOOK_POST + #undef SHIFT_OP_64_BIT_HOOK_POST + #define SHIFT_OP_32_BIT_HOOK_PRE + #define SHIFT_OP_64_BIT_HOOK_PRE + #define SHIFT_OP_32_BIT_HOOK_POST + #define SHIFT_OP_64_BIT_HOOK_POST + break; + case SpvOpShiftLeftLogical: + // zero fill left shift. Just << in c + DO_SHIFT_OPERATION(evaluation_mode, p_parser, p_eval, p_node, << , res, CLEANUP) + break; + case SpvOpBitwiseOr: + DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, | , res, CLEANUP) + break; + case SpvOpBitwiseXor: + DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, ^, res, CLEANUP) + break; + case SpvOpBitwiseAnd: + DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, &, res, CLEANUP) + break; + + case SpvOpVectorShuffle: + { + switch (evaluation_mode) { + default: + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; + SpvReflectPrvEvaluationNode* operand2 = p_node->id_operands[1]; + for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { + uint8_t mapped_component = p_node->instruction_private.vector_shuffle.idx[i]; + if (mapped_component == 0xff) { + result->data.numeric.vector.value[i].undefined_value = 1; + } + else if (mapped_component < operand1->value.type->traits.numeric.vector.component_count) { + EVALUATE_OPERAND(operand1, res, CLEANUP) + result->data.numeric.vector.value[i] = operand1->value.data.numeric.vector.value[mapped_component]; + } + else { + EVALUATE_OPERAND(operand2, res, CLEANUP) + result->data.numeric.vector.value[i] = operand2->value.data.numeric.vector.value[mapped_component - operand1->value.type->traits.numeric.vector.component_count]; + } + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + CHECK_IS_INTEGER_TYPE(p_node, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) + if (!(result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + CHECK_INSTRUCTION_SIZE(p_parser_node, 6 + p_node->value.type->traits.numeric.vector.component_count) + + if (p_node->value.type->traits.numeric.vector.component_count > SPV_REFLECT_MAX_VECTOR_DIMS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + + p_node->num_id_operands = 2; + p_node->num_literal_words = 0; + + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { + GET_OPERAND(p_parser, p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) + if (!(p_node->id_operands[0]->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + if (p_node->id_operands[0]->value.type->component_type_id != p_node->value.type->component_type_id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + if (p_node->id_operands[0]->value.type->traits.numeric.vector.component_count > SPV_REFLECT_MAX_VECTOR_DIMS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + + GET_OPERAND(p_parser, p_eval, p_node, 5, p_node->id_operands[1], res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[1], res, CLEANUP) + if (!(p_node->id_operands[1]->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + if (p_node->id_operands[1]->value.type->component_type_id != p_node->value.type->component_type_id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + if (p_node->id_operands[1]->value.type->traits.numeric.vector.component_count > SPV_REFLECT_MAX_VECTOR_DIMS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + + uint32_t max_index = p_node->id_operands[0]->value.type->traits.numeric.vector.component_count + p_node->id_operands[1]->value.type->traits.numeric.vector.component_count; + + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + for (uint32_t i = 0; i < p_node->value.type->traits.numeric.vector.component_count; ++i) { + uint32_t idx; + EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 6 + i, idx, res, CLEANUP); + if (idx == 0xffffffff) { + p_node->instruction_private.vector_shuffle.idx[i] = 0xff; + } + else { + if (idx >= max_index) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; } - break; - } + p_node->instruction_private.vector_shuffle.idx[i] = (uint8_t)idx; + } + } + } + break; + } } break; - case SpvOpSpecConstantOp: + + case SpvOpCompositeExtract: + // only support vector types for now... { - // operation has result type id, thus must be typed + switch (evaluation_mode) { + default: + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + EVALUATE_OPERAND(p_node->id_operands[0], res, CLEANUP) + SpvReflectValueData* current_data = p_node->instruction_private.composite_extract.src_data; + SpvReflectTypeDescription* current_type = p_node->instruction_private.composite_extract.src_type; + res = CopyValueData(current_type, &result->data, current_data); + if (res != SPV_REFLECT_RESULT_SUCCESS) { + goto CLEANUP; + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + if (p_node->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } - // only vector and scalar types of int/bool/float types implemented - // only OpSelect, OpUndef and access chain instructions can work with non-vector or scalar types - // they are not currently supported... (likely never will) - if (result->type->type_flags & VECTOR_DISALLOWED_FLAGS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; - goto CLEANUP; - } - if (evaluation_mode == SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS) { + CHECK_IS_INTEGER_TYPE(p_node, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) + if (!(result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; - EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 3, p_node->specOp, res, CLEANUP); - } - - switch (p_node->specOp) { - default: - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + if (p_parser_node->word_count < 5) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + goto CLEANUP; + } + p_node->num_id_operands = 1; + p_node->num_literal_words = p_parser_node->word_count - 5; + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { + + GET_OPERAND(p_parser, p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) + if (p_node->id_operands[0]->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + SpvReflectValueData* current_data = &p_node->id_operands[0]->value.data; + SpvReflectTypeDescription* current_type = p_node->id_operands[0]->value.type; + for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { + uint32_t member_index; + EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 5 + i, member_index, res, CLEANUP); + p_node->literal_words[i] = member_index; + res = GetMemberByIndex(p_eval->member_type_finder, current_data, current_type, member_index, ¤t_data, ¤t_type); + if (res != SPV_REFLECT_RESULT_SUCCESS) { goto CLEANUP; - case SpvOpUndef: - // write undefined value to result... - { - switch (evaluation_mode) { - default: - { - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; - goto CLEANUP; - } - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: - { - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - for (uint32_t i = 0; i < result->type->traits.numeric.vector.component_count; ++i) { - result->data.numeric.vector.value[i].undefined_value = 1; - } - } - else { - result->data.numeric.scalar.undefined_value = 1; - } - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: - { - SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; - CHECK_INSTRUCTION_SIZE(p_parser_node, 4) - p_node->num_id_operands = 0; - p_node->num_literal_words = 0; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VOID) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: - break; - } - } - break; - case SpvOpSConvert: - // sign extend or truncate integers. - // result is scalar or vector integer type. - // vectors should be of same length - { - switch (evaluation_mode) { - default: - { - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; - goto CLEANUP; - } - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: - { - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - vec_size = result->type->traits.numeric.vector.component_count; - } - SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; - EVALUATE_OPERAND(operand1, res, CLEANUP) - for (uint32_t i = 0; i < vec_size; ++i) { - result->data.numeric.vector.value[i].undefined_value = operand1->value.data.numeric.vector.value[i].undefined_value; - switch (operand1->value.type->traits.numeric.scalar.width) { - default: - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - case 32: - { - int32_t data = operand1->value.data.numeric.vector.value[i].value.sint32_value; - switch (result->type->traits.numeric.scalar.width) { - default: - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - case 32: - result->data.numeric.vector.value[i].value.sint32_value = data; - break; - case 64: - result->data.numeric.vector.value[i].value.sint64_value = (int64_t)data; - break; - } - } - break; - case 64: - { - int64_t data = operand1->value.data.numeric.vector.value[i].value.sint64_value; - switch (result->type->traits.numeric.scalar.width) { - default: - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - case 32: - result->data.numeric.vector.value[i].value.sint32_value = (int32_t)data; - break; - case 64: - result->data.numeric.vector.value[i].value.sint64_value = data; - break; - } - } - break; - } - } - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: - { - SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; - CHECK_INSTRUCTION_SIZE(p_parser_node, 5) - p_node->num_id_operands = 1; - p_node->num_literal_words = 0; - - // check result type - CHECK_IS_INTEGER_TYPE(p_node, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: - { - GET_OPERAND(p_parser, p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) - CHECK_IS_INTEGER_TYPE(p_node->id_operands[0], res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) - - // operand must be signed - if (!p_node->id_operands[0]->value.type->traits.numeric.scalar.signedness) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - uint32_t vec_size = 1; - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_node, p_node->id_operands[0], res, CLEANUP) - } - break; - } - } - break; - case SpvOpUConvert: - // zero extend or truncate integers. - // result is scalar or vector integer type. - // vectors should be of same length - { - switch (evaluation_mode) { - default: - { - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; - goto CLEANUP; - } - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: - { - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - vec_size = result->type->traits.numeric.vector.component_count; - } - SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; - EVALUATE_OPERAND(operand1, res, CLEANUP) - for (uint32_t i = 0; i < vec_size; ++i) { - result->data.numeric.vector.value[i].undefined_value = operand1->value.data.numeric.vector.value[i].undefined_value; - switch (operand1->value.type->traits.numeric.scalar.width) { - default: - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - case 32: - { - uint32_t data = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value; - switch (result->type->traits.numeric.scalar.width) { - default: - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - case 32: - result->data.numeric.vector.value[i].value.uint32_bool_value = data; - break; - case 64: - result->data.numeric.vector.value[i].value.uint64_value = (uint64_t)data; - break; - } - } - break; - case 64: - { - uint64_t data = operand1->value.data.numeric.vector.value[i].value.uint64_value; - switch (result->type->traits.numeric.scalar.width) { - default: - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - case 32: - result->data.numeric.vector.value[i].value.uint32_bool_value = (uint32_t)data; - break; - case 64: - result->data.numeric.vector.value[i].value.uint64_value = data; - break; - } - } - break; - } - } - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: - { - SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; - CHECK_INSTRUCTION_SIZE(p_parser_node, 5) - p_node->num_id_operands = 1; - p_node->num_literal_words = 0; - - // check result type - CHECK_IS_INTEGER_TYPE(p_node, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: - { - GET_OPERAND(p_parser, p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) - CHECK_IS_INTEGER_TYPE(p_node->id_operands[0], res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) - - // operand must be unsigned - if (p_node->id_operands[0]->value.type->traits.numeric.scalar.signedness) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - uint32_t vec_size = 1; - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_node, p_node->id_operands[0], res, CLEANUP) - } - break; - } - } - break; - case SpvOpFConvert: - // convert of floating point integer to any integer of different width. - // just 32 and 64 bit for now... - { - switch (evaluation_mode) { - default: - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; - goto CLEANUP; - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: - { - uint32_t vec_size = 1; - if (result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - vec_size = result->type->traits.numeric.vector.component_count; - } - SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; - EVALUATE_OPERAND(operand1, res, CLEANUP) - // now do the job - for (uint32_t i = 0; i < vec_size; ++i) { - result->data.numeric.vector.value[i].undefined_value = operand1->value.data.numeric.vector.value[i].undefined_value; - switch (operand1->value.type->traits.numeric.scalar.width) { - default: - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - case 32: - // convert int32 to generic integer type - switch (result->type->traits.numeric.scalar.width) { - default: - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - case 32: - result->data.numeric.vector.value[i].value.float32_value = operand1->value.data.numeric.vector.value[i].value.float32_value; - break; - case 64: - result->data.numeric.vector.value[i].value.float64_value = (double)operand1->value.data.numeric.vector.value[i].value.float32_value; - break; - } - break; - case 64: - // convert int64 to generic integer type - switch (result->type->traits.numeric.scalar.width) { - default: - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - case 32: - result->data.numeric.vector.value[i].value.float32_value = (float)operand1->value.data.numeric.vector.value[i].value.float64_value; - break; - case 64: - result->data.numeric.vector.value[i].value.float64_value = operand1->value.data.numeric.vector.value[i].value.float64_value; - break; - } - } - } - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: - { - SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; - CHECK_INSTRUCTION_SIZE(p_parser_node, 5) - p_node->num_id_operands = 1; - p_node->num_literal_words = 0; - - // check result type - CHECK_IS_FLOAT_TYPE(p_node, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: - { - GET_OPERAND(p_parser, p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) - CHECK_IS_FLOAT_TYPE(p_node->id_operands[0], res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) - - // vector size must match - uint32_t vec_size = 1; - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_node, p_node->id_operands[0], res, CLEANUP) - } - break; - } - } - break; - case SpvOpSNegate: - #undef SIMPLE_UNARY_OP_32_BIT_HOOK - #undef SIMPLE_UNARY_OP_64_BIT_HOOK - #define SIMPLE_UNARY_OP_32_BIT_HOOK {data = -data;} - #define SIMPLE_UNARY_OP_64_BIT_HOOK {data = -data;} - DO_SIMPLE_UNARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, res, CLEANUP) - #undef SIMPLE_UNARY_OP_32_BIT_HOOK - #undef SIMPLE_UNARY_OP_64_BIT_HOOK - #define SIMPLE_UNARY_OP_32_BIT_HOOK - #define SIMPLE_UNARY_OP_64_BIT_HOOK - break; - case SpvOpNot: - // bitwise not of every component in op1, store into same width result. - #undef SIMPLE_UNARY_OP_32_BIT_HOOK - #undef SIMPLE_UNARY_OP_64_BIT_HOOK - #define SIMPLE_UNARY_OP_32_BIT_HOOK data ^= 0xffffffff; - #define SIMPLE_UNARY_OP_64_BIT_HOOK data ^= 0xffffffffffffffff; - DO_SIMPLE_UNARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, res, CLEANUP) - #undef SIMPLE_UNARY_OP_32_BIT_HOOK - #undef SIMPLE_UNARY_OP_64_BIT_HOOK - #define SIMPLE_UNARY_OP_32_BIT_HOOK - #define SIMPLE_UNARY_OP_64_BIT_HOOK - break; - case SpvOpIAdd: - // integer add. - // subtraction result is the same for 2-compliment - DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, +, res, CLEANUP) - break; - case SpvOpISub: - // integer subtract. - // subtraction result is the same for 2-compliment - DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, -, res, CLEANUP) - break; - case SpvOpIMul: - // integer multiply... - // imul instruction on x86, signed and unsigned have no difference in result - // except for how they overflow. - DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, *, res, CLEANUP) - break; - case SpvOpUDiv: - // unsigned divide - // All operand must be same unsigned integer scalar or vector type. - // x86 div instruction - // emits undefined value if divide by zero - DO_UNSIGNED_INTEGER_DIVISION(evaluation_mode, p_parser, p_eval, p_node, /, res, CLEANUP) - break; - case SpvOpSDiv: - // signed divide - // x86 idiv instruction - // same bits, same vector size, no sign requirements. - // accessing result types that are not signed violates strict aliasing rules. - // emits undefined value if divide by zero or 0x80000... divides -1 - #undef SIMPLE_BINARY_OP_32_BIT_HOOK - #define SIMPLE_BINARY_OP_32_BIT_HOOK \ - if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ - p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ - } - #undef SIMPLE_BINARY_OP_64_BIT_HOOK - #define SIMPLE_BINARY_OP_64_BIT_HOOK \ - if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ - p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ - } - DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, /, res, CLEANUP) - #undef SIMPLE_BINARY_OP_32_BIT_HOOK - #undef SIMPLE_BINARY_OP_64_BIT_HOOK - #define SIMPLE_BINARY_OP_32_BIT_HOOK - #define SIMPLE_BINARY_OP_64_BIT_HOOK - break; - case SpvOpUMod: - // unsigned modulo - // all types must be same unsigned integer scalar or vector type. - DO_UNSIGNED_INTEGER_DIVISION(evaluation_mode, p_parser, p_eval, p_node, %, res, CLEANUP) - break; - case SpvOpSRem: - // just the result of % operator. - #undef SIMPLE_BINARY_OP_32_BIT_HOOK - #define SIMPLE_BINARY_OP_32_BIT_HOOK \ - if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ - p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ - } - #undef SIMPLE_BINARY_OP_64_BIT_HOOK - #define SIMPLE_BINARY_OP_64_BIT_HOOK \ - if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ - p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ - } - DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, %, res, CLEANUP) - #undef SIMPLE_BINARY_OP_32_BIT_HOOK - #undef SIMPLE_BINARY_OP_64_BIT_HOOK - #define SIMPLE_BINARY_OP_32_BIT_HOOK - #define SIMPLE_BINARY_OP_64_BIT_HOOK - break; - case SpvOpSMod: - // not result of % operator, need adjusting with dividend... - #undef SIMPLE_BINARY_OP_32_BIT_HOOK - #define SIMPLE_BINARY_OP_32_BIT_HOOK \ - if (data2 == 0 || (data2 == -1 && data1 == (int32_t)0x80000000)) { \ - p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - else if (data != 0) { \ - int sign1 = 0, sign2 = 0; \ - if (data < 0) sign1 = 1; \ - if (data2 < 0) sign2 = 1; \ - /* remainder is not same as modulo here...*/ \ - if ((sign1 + sign2) == 1) { \ - data += data2; \ - } \ - } - #undef SIMPLE_BINARY_OP_64_BIT_HOOK - #define SIMPLE_BINARY_OP_64_BIT_HOOK \ - if (data2 == 0 || (data2 == -1 && data1 == (int64_t)0x8000000000000000)) { \ - p_node->value.data.numeric.vector.value[i].undefined_value = 1; \ - } \ - else if (data != 0) { \ - int sign1 = 0, sign2 = 0; \ - if (data < 0) sign1 = 1; \ - if (data2 < 0) sign2 = 1; \ - /* remainder is not same as modulo here...*/ \ - if ((sign1 + sign2) == 1) { \ - data += data2; \ - } \ - } - DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, %, res, CLEANUP) - #undef SIMPLE_BINARY_OP_32_BIT_HOOK - #undef SIMPLE_BINARY_OP_64_BIT_HOOK - #define SIMPLE_BINARY_OP_32_BIT_HOOK - #define SIMPLE_BINARY_OP_64_BIT_HOOK - break; - case SpvOpShiftRightLogical: - // zero fill right shift. Just >> in c - DO_SHIFT_OPERATION(evaluation_mode, p_parser, p_eval, p_node, >>, res, CLEANUP) - break; - case SpvOpShiftRightArithmetic: - // fill with sign of original number. - #undef SHIFT_OP_32_BIT_HOOK_PRE - #undef SHIFT_OP_64_BIT_HOOK_PRE - #undef SHIFT_OP_32_BIT_HOOK_POST - #undef SHIFT_OP_64_BIT_HOOK_POST - #define SHIFT_OP_32_BIT_HOOK_PRE uint32_t sign_bit = data & 0x80000000; - #define SHIFT_OP_64_BIT_HOOK_PRE uint64_t sign_bit = data & 0x8000000000000000; - #define SHIFT_OP_32_BIT_HOOK_POST \ - if (sign_bit) { \ - uint32_t fill = 0xffffffff << (32 - shift_num); \ - data |= fill; \ - } - #define SHIFT_OP_64_BIT_HOOK_POST \ - if (sign_bit) { \ - uint64_t fill = 0xffffffffffffffff << (64 - shift_num); \ - data |= fill; \ - } - DO_SHIFT_OPERATION(evaluation_mode, p_parser, p_eval, p_node, >> , res, CLEANUP) - #undef SHIFT_OP_32_BIT_HOOK_PRE - #undef SHIFT_OP_64_BIT_HOOK_PRE - #undef SHIFT_OP_32_BIT_HOOK_POST - #undef SHIFT_OP_64_BIT_HOOK_POST - #define SHIFT_OP_32_BIT_HOOK_PRE - #define SHIFT_OP_64_BIT_HOOK_PRE - #define SHIFT_OP_32_BIT_HOOK_POST - #define SHIFT_OP_64_BIT_HOOK_POST - break; - case SpvOpShiftLeftLogical: - // zero fill left shift. Just << in c - DO_SHIFT_OPERATION(evaluation_mode, p_parser, p_eval, p_node, << , res, CLEANUP) - break; - case SpvOpBitwiseOr: - DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, |, res, CLEANUP) - break; - case SpvOpBitwiseXor: - DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, ^ , res, CLEANUP) - break; - case SpvOpBitwiseAnd: - DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, & , res, CLEANUP) - break; - - case SpvOpVectorShuffle: - { - switch (evaluation_mode) { - default: - { - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; - goto CLEANUP; - } - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: - { - SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; - SpvReflectPrvEvaluationNode* operand2 = p_node->id_operands[1]; - for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { - uint8_t mapped_component = p_node->instruction_private.vector_shuffle.idx[i]; - if (mapped_component == 0xff) { - result->data.numeric.vector.value[i].undefined_value = 1; - } - else if (mapped_component < operand1->value.type->traits.numeric.vector.component_count) { - EVALUATE_OPERAND(operand1, res, CLEANUP) - result->data.numeric.vector.value[i] = operand1->value.data.numeric.vector.value[mapped_component]; - } - else { - EVALUATE_OPERAND(operand2, res, CLEANUP) - result->data.numeric.vector.value[i] = operand2->value.data.numeric.vector.value[mapped_component - operand1->value.type->traits.numeric.vector.component_count]; - } - } - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: - { - CHECK_IS_INTEGER_TYPE(p_node, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) - if (!(result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - - SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; - CHECK_INSTRUCTION_SIZE(p_parser_node, 6 + p_node->value.type->traits.numeric.vector.component_count) - - if (p_node->value.type->traits.numeric.vector.component_count > SPV_REFLECT_MAX_VECTOR_DIMS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - - p_node->num_id_operands = 2; - p_node->num_literal_words = 0; - - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: - { - GET_OPERAND(p_parser, p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) - if (!(p_node->id_operands[0]->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - if(p_node->id_operands[0]->value.type->component_type_id != p_node->value.type->component_type_id){ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - if (p_node->id_operands[0]->value.type->traits.numeric.vector.component_count > SPV_REFLECT_MAX_VECTOR_DIMS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - - GET_OPERAND(p_parser, p_eval,p_node, 5, p_node->id_operands[1], res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[1], res, CLEANUP) - if (!(p_node->id_operands[1]->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - if(p_node->id_operands[1]->value.type->component_type_id != p_node->value.type->component_type_id){ - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - if (p_node->id_operands[1]->value.type->traits.numeric.vector.component_count > SPV_REFLECT_MAX_VECTOR_DIMS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - - uint32_t max_index = p_node->id_operands[0]->value.type->traits.numeric.vector.component_count + p_node->id_operands[1]->value.type->traits.numeric.vector.component_count; - - SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; - for(uint32_t i = 0; i< p_node->value.type->traits.numeric.vector.component_count; ++i) { - uint32_t idx; - EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 6 + i, idx, res, CLEANUP); - if (idx == 0xffffffff) { - p_node->instruction_private.vector_shuffle.idx[i] = 0xff; - } - else { - if (idx >= max_index) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - p_node->instruction_private.vector_shuffle.idx[i] = (uint8_t)idx; - } - } - } - break; - } - } - break; - - case SpvOpCompositeExtract: - // only support vector types for now... - { - switch (evaluation_mode) { - default: - { - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; - goto CLEANUP; - } - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: - { - EVALUATE_OPERAND(p_node->id_operands[0], res, CLEANUP) - SpvReflectValueData* current_data = p_node->instruction_private.composite_extract.src_data; - SpvReflectTypeDescription* current_type = p_node->instruction_private.composite_extract.src_type; - res = CopyValueData(current_type, &result->data, current_data); - if (res != SPV_REFLECT_RESULT_SUCCESS) { - goto CLEANUP; - } - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: - { - if (p_node->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - - CHECK_IS_INTEGER_TYPE(p_node, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) - if (!(result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; - if(p_parser_node->word_count < 5) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; - goto CLEANUP; - } - p_node->num_id_operands = 1; - p_node->num_literal_words = p_parser_node->word_count - 5; - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: - { - - GET_OPERAND(p_parser, p_eval,p_node, 4, p_node->id_operands[0], res, CLEANUP) - if (p_node->id_operands[0]->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - - SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; - SpvReflectValueData* current_data = &p_node->id_operands[0]->value.data; - SpvReflectTypeDescription* current_type = p_node->id_operands[0]->value.type; - for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { - uint32_t member_index; - EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 5 + i, member_index, res, CLEANUP); - p_node->literal_words[i] = member_index; - res = GetMemberByIndex(p_eval->member_type_finder, current_data, current_type, member_index, ¤t_data, ¤t_type); - if (res != SPV_REFLECT_RESULT_SUCCESS) { - goto CLEANUP; - } - } - if (current_type->id != p_node->value.type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - - p_node->instruction_private.composite_extract.src_data = current_data; - p_node->instruction_private.composite_extract.src_type = current_type; - } - break; - } + } + } + if (current_type->id != p_node->value.type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + + p_node->instruction_private.composite_extract.src_data = current_data; + p_node->instruction_private.composite_extract.src_type = current_type; + } + break; + } + } + break; + case SpvOpCompositeInsert: + { + switch (evaluation_mode) { + default: + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + EVALUATE_OPERAND(p_node->id_operands[0], res, CLEANUP) + res = CopyValueData(p_node->value.type, &p_node->value.data, &p_node->id_operands[0]->value.data); + if (res != SPV_REFLECT_RESULT_SUCCESS) { + goto CLEANUP; + } + + EVALUATE_OPERAND(p_node->id_operands[1], res, CLEANUP) + res = CopyValueData(p_node->instruction_private.composite_insert.dst_type, + p_node->instruction_private.composite_insert.dst_data, &p_node->id_operands[1]->value.data); + if (res != SPV_REFLECT_RESULT_SUCCESS) { + goto CLEANUP; + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + if (p_node->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + + CHECK_IS_INTEGER_TYPE(p_node, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) + if (!(result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + if (p_parser_node->word_count < 6) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + goto CLEANUP; + } + p_node->num_id_operands = 2; + p_node->num_literal_words = p_parser_node->word_count - 6; + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { + // the value to modify to + GET_OPERAND(p_parser, p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) + if (p_node->id_operands[0]->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + + // the original value + GET_OPERAND(p_parser, p_eval, p_node, 5, p_node->id_operands[1], res, CLEANUP) + if (p_node->id_operands[1]->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + + if (p_node->id_operands[1]->value.type->id != p_node->value.type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + SpvReflectValueData* current_data = &result->data; + SpvReflectTypeDescription* current_type = result->type; + for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { + uint32_t member_index; + EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 6 + i, member_index, res, CLEANUP); + p_node->literal_words[i] = member_index; + res = GetMemberByIndex(p_eval->member_type_finder, current_data, current_type, member_index, ¤t_data, ¤t_type); + if (res != SPV_REFLECT_RESULT_SUCCESS) { + goto CLEANUP; + } + } + if (current_type->id != p_node->id_operands[0]->value.type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + + p_node->instruction_private.composite_insert.dst_data = current_data; + p_node->instruction_private.composite_insert.dst_type = current_type; + } + break; + } + } + break; + + case SpvOpLogicalOr: + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, || , res, CLEANUP) + break; + case SpvOpLogicalAnd: + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, &&, res, CLEANUP) + break; + case SpvOpLogicalNot: + { + switch (evaluation_mode) { + default: + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + uint32_t vec_size = 1; + if (p_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + vec_size = p_node->value.type->traits.numeric.vector.component_count; + } + SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; + EVALUATE_OPERAND(operand1, res, CLEANUP) + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1->value.data.numeric.vector.value[i].undefined_value) { + result->data.numeric.vector.value[i].undefined_value = 1; + } + result->data.numeric.vector.value[i].value.uint32_bool_value = !operand1->value.data.numeric.vector.value[i].value.uint32_bool_value; + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + CHECK_INSTRUCTION_SIZE(p_parser_node, 5) + p_node->num_id_operands = 1; + p_node->num_literal_words = 0; + + /* check result type */ + CHECK_IS_BOOLEAN_TYPE(p_node, res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) + if (p_node->value.type->traits.numeric.scalar.signedness) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { + GET_OPERAND(p_parser, p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) + CHECK_IS_BOOLEAN_TYPE(p_node->id_operands[0], res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) + + uint32_t vec_size = 1; + CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_node, p_node->id_operands[0], res, CLEANUP) + } + break; + } + } + break; + case SpvOpLogicalEqual: + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, == , res, CLEANUP) + break; + case SpvOpLogicalNotEqual: + DO_BINARY_BOOLEAN_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, != , res, CLEANUP) + break; + case SpvOpSelect: + // same as c/cpp code: a ? b : c; + // should allow composite types if not for spec-constant since 1.4 + { + switch (evaluation_mode) { + default: + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + goto CLEANUP; + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + { + SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; + SpvReflectPrvEvaluationNode* operand2 = p_node->id_operands[1]; + SpvReflectPrvEvaluationNode* operand3 = p_node->id_operands[2]; + EVALUATE_OPERAND(operand1, res, CLEANUP); + if (operand1->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + uint32_t vec_size = operand1->value.type->traits.numeric.vector.component_count; + for (uint32_t i = 0; i < vec_size; ++i) { + if (operand1->value.data.numeric.vector.value[i].undefined_value) { + result->data.numeric.vector.value[i].undefined_value = 1; } - break; - case SpvOpCompositeInsert: - { - switch (evaluation_mode) { - default: - { - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; - goto CLEANUP; - } - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: - { - EVALUATE_OPERAND(p_node->id_operands[0],res,CLEANUP) - res = CopyValueData(p_node->value.type, &p_node->value.data, &p_node->id_operands[0]->value.data); - if (res != SPV_REFLECT_RESULT_SUCCESS) { - goto CLEANUP; - } - - EVALUATE_OPERAND(p_node->id_operands[1], res, CLEANUP) - res = CopyValueData(p_node->instruction_private.composite_insert.dst_type, - p_node->instruction_private.composite_insert.dst_data, &p_node->id_operands[1]->value.data); - if (res != SPV_REFLECT_RESULT_SUCCESS) { - goto CLEANUP; - } - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: - { - if (p_node->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - - CHECK_IS_INTEGER_TYPE(p_node, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) - if (!(result->type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - - SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; - if (p_parser_node->word_count < 6) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; - goto CLEANUP; - } - p_node->num_id_operands = 2; - p_node->num_literal_words = p_parser_node->word_count - 6; - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: - { - // the value to modify to - GET_OPERAND(p_parser, p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) - if (p_node->id_operands[0]->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - - // the original value - GET_OPERAND(p_parser, p_eval, p_node, 5, p_node->id_operands[1], res, CLEANUP) - if (p_node->id_operands[1]->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - - if (p_node->id_operands[1]->value.type->id != p_node->value.type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; - SpvReflectValueData* current_data = &result->data; - SpvReflectTypeDescription* current_type = result->type; - for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { - uint32_t member_index; - EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 6 + i, member_index, res, CLEANUP); - p_node->literal_words[i] = member_index; - res = GetMemberByIndex(p_eval->member_type_finder, current_data, current_type, member_index, ¤t_data, ¤t_type); - if (res != SPV_REFLECT_RESULT_SUCCESS) { - goto CLEANUP; - } - } - if (current_type->id != p_node->id_operands[0]->value.type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - - p_node->instruction_private.composite_insert.dst_data = current_data; - p_node->instruction_private.composite_insert.dst_type = current_type; - } - break; - } + if (operand1->value.data.numeric.vector.value[i].value.uint32_bool_value) { + EVALUATE_OPERAND(operand2, res, CLEANUP) + if (operand2->value.data.numeric.vector.value[i].undefined_value) { + result->data.numeric.vector.value[i].undefined_value = 1; + } + result->data.numeric.vector.value[i].value = operand2->value.data.numeric.vector.value[i].value; } - break; - - case SpvOpLogicalOr: - DO_BINARY_BOOLEAN_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, ||, res, CLEANUP) - break; - case SpvOpLogicalAnd: - DO_BINARY_BOOLEAN_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, && , res, CLEANUP) - break; - case SpvOpLogicalNot: - { - switch (evaluation_mode) { - default: - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; - goto CLEANUP; - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: - { - uint32_t vec_size = 1; - if (p_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - vec_size = p_node->value.type->traits.numeric.vector.component_count; - } - SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; - EVALUATE_OPERAND(operand1, res, CLEANUP) - for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1->value.data.numeric.vector.value[i].undefined_value) { - result->data.numeric.vector.value[i].undefined_value = 1; - } - result->data.numeric.vector.value[i].value.uint32_bool_value = !operand1->value.data.numeric.vector.value[i].value.uint32_bool_value; - } - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: - { - SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; - CHECK_INSTRUCTION_SIZE(p_parser_node, 5) - p_node->num_id_operands = 1; - p_node->num_literal_words = 0; - - /* check result type */ - CHECK_IS_BOOLEAN_TYPE(p_node, res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(p_node, res, CLEANUP) - if (p_node->value.type->traits.numeric.scalar.signedness) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: - { - GET_OPERAND(p_parser, p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) - CHECK_IS_BOOLEAN_TYPE(p_node->id_operands[0], res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) - - uint32_t vec_size = 1; - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_node, p_node->id_operands[0], res, CLEANUP) - } - break; - } + else { + EVALUATE_OPERAND(operand3, res, CLEANUP) + if (operand3->value.data.numeric.vector.value[i].undefined_value) { + result->data.numeric.vector.value[i].undefined_value = 1; + } + result->data.numeric.vector.value[i].value = operand3->value.data.numeric.vector.value[i].value; } - break; - case SpvOpLogicalEqual: - DO_BINARY_BOOLEAN_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, ==, res, CLEANUP) - break; - case SpvOpLogicalNotEqual: - DO_BINARY_BOOLEAN_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, != , res, CLEANUP) - break; - case SpvOpSelect: - // same as c/cpp code: a ? b : c; - // should allow composite types if not for spec-constant since 1.4 - { - switch (evaluation_mode) { - default: - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; - goto CLEANUP; - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: - { - SpvReflectPrvEvaluationNode* operand1 = p_node->id_operands[0]; - SpvReflectPrvEvaluationNode* operand2 = p_node->id_operands[1]; - SpvReflectPrvEvaluationNode* operand3 = p_node->id_operands[2]; - EVALUATE_OPERAND(operand1, res, CLEANUP); - if(operand1->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR){ - uint32_t vec_size = operand1->value.type->traits.numeric.vector.component_count; - for (uint32_t i = 0; i < vec_size; ++i) { - if (operand1->value.data.numeric.vector.value[i].undefined_value) { - result->data.numeric.vector.value[i].undefined_value = 1; - } - if (operand1->value.data.numeric.vector.value[i].value.uint32_bool_value) { - EVALUATE_OPERAND(operand2, res, CLEANUP) - if (operand2->value.data.numeric.vector.value[i].undefined_value) { - result->data.numeric.vector.value[i].undefined_value = 1; - } - result->data.numeric.vector.value[i].value = operand2->value.data.numeric.vector.value[i].value; - } - else { - EVALUATE_OPERAND(operand3, res, CLEANUP) - if (operand3->value.data.numeric.vector.value[i].undefined_value) { - result->data.numeric.vector.value[i].undefined_value = 1; - } - result->data.numeric.vector.value[i].value = operand3->value.data.numeric.vector.value[i].value; - } - } - } - else { - if(operand1->value.data.numeric.scalar.value.uint32_bool_value) { - EVALUATE_OPERAND(operand2, res, CLEANUP) - result->data = operand2->value.data; - } - else { - EVALUATE_OPERAND(operand3, res, CLEANUP) - result->data = operand3->value.data; - } - if (operand1->value.data.numeric.scalar.undefined_value) { - // we shouldn't care about content here... - for (uint32_t i = 0; i < SPV_REFLECT_MAX_VECTOR_DIMS; ++i) { - result->data.numeric.vector.value[i].undefined_value = 1; - } - } - } - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: - { - SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; - CHECK_INSTRUCTION_SIZE(p_parser_node, 7) - p_node->num_id_operands = 3; - p_node->num_literal_words = 0; - - // check result type - if (p_node->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - } - break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: - { - GET_OPERAND(p_parser, p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) - CHECK_IS_BOOLEAN_TYPE(p_node->id_operands[0], res, CLEANUP) - CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) - - GET_OPERAND(p_parser, p_eval, p_node, 5, p_node->id_operands[1], res, CLEANUP) - if (p_node->id_operands[1]->value.type->id != p_node->value.type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - - GET_OPERAND(p_parser, p_eval, p_node, 6, p_node->id_operands[2], res, CLEANUP) - if (p_node->id_operands[2]->value.type->id != p_node->value.type->id) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - - if (p_node->id_operands[0]->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { - // spec says only about "component" selection, but we only deal with vector for now... - if(p_node->value.type->type_flags & VECTOR_DISALLOWED_FLAGS) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; - goto CLEANUP; - } - if(p_node->value.type->traits.numeric.vector.component_count != p_node->id_operands[0]->value.type->traits.numeric.vector.component_count) { - res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - goto CLEANUP; - } - } - else { - // no checking is needed for now... - } - } - break; - } + } + } + else { + if (operand1->value.data.numeric.scalar.value.uint32_bool_value) { + EVALUATE_OPERAND(operand2, res, CLEANUP) + result->data = operand2->value.data; + } + else { + EVALUATE_OPERAND(operand3, res, CLEANUP) + result->data = operand3->value.data; + } + if (operand1->value.data.numeric.scalar.undefined_value) { + // we shouldn't care about content here... + for (uint32_t i = 0; i < SPV_REFLECT_MAX_VECTOR_DIMS; ++i) { + result->data.numeric.vector.value[i].undefined_value = 1; } - break; - case SpvOpIEqual: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, ==, res, CLEANUP) - break; - case SpvOpINotEqual: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, != , res, CLEANUP) - break; - case SpvOpULessThan: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, < , res, CLEANUP) - break; - case SpvOpSLessThan: - DO_BINARY_SINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, < , res, CLEANUP) - break; - case SpvOpUGreaterThan: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, > , res, CLEANUP) - break; - case SpvOpSGreaterThan: - DO_BINARY_SINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, > , res, CLEANUP) - break; - case SpvOpULessThanEqual: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, <= , res, CLEANUP) - break; - case SpvOpSLessThanEqual: - DO_BINARY_SINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, <= , res, CLEANUP) - break; - case SpvOpUGreaterThanEqual: - DO_BINARY_UINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, >= , res, CLEANUP) - break; - case SpvOpSGreaterThanEqual: - DO_BINARY_SINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, >= , res, CLEANUP) - break; - - // check shader capability... vulkan should assume this... - case SpvOpQuantizeToF16: - res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; - break; - - // check kernel capability... vulkan have none currently... - case SpvOpConvertFToS: case SpvOpConvertSToF: - case SpvOpConvertFToU: case SpvOpConvertUToF: - case SpvOpConvertPtrToU: case SpvOpConvertUToPtr: - case SpvOpGenericCastToPtr: case SpvOpPtrCastToGeneric: - case SpvOpBitcast: case SpvOpFNegate: - case SpvOpFAdd: case SpvOpFSub: case SpvOpFMul: case SpvOpFDiv: - case SpvOpFRem: case SpvOpFMod: - case SpvOpAccessChain: case SpvOpInBoundsAccessChain: - case SpvOpPtrAccessChain: case SpvOpInBoundsPtrAccessChain: + } + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + { + SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; + CHECK_INSTRUCTION_SIZE(p_parser_node, 7) + p_node->num_id_operands = 3; + p_node->num_literal_words = 0; + + // check result type + if (p_node->value.type->type_flags & COMPOSITE_DISALLOWED_FLAGS) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + { + GET_OPERAND(p_parser, p_eval, p_node, 4, p_node->id_operands[0], res, CLEANUP) + CHECK_IS_BOOLEAN_TYPE(p_node->id_operands[0], res, CLEANUP) + CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) + + GET_OPERAND(p_parser, p_eval, p_node, 5, p_node->id_operands[1], res, CLEANUP) + if (p_node->id_operands[1]->value.type->id != p_node->value.type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + + GET_OPERAND(p_parser, p_eval, p_node, 6, p_node->id_operands[2], res, CLEANUP) + if (p_node->id_operands[2]->value.type->id != p_node->value.type->id) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + + if (p_node->id_operands[0]->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { + // spec says only about "component" selection, but we only deal with vector for now... + if (p_node->value.type->type_flags & VECTOR_DISALLOWED_FLAGS) { res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; - break; - } + goto CLEANUP; + } + if (p_node->value.type->traits.numeric.vector.component_count != p_node->id_operands[0]->value.type->traits.numeric.vector.component_count) { + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + goto CLEANUP; + } + } + else { + // no checking is needed for now... + } + } + break; + } } break; - } - CLEANUP: - switch(evaluation_mode) { - default: - res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; - p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED; - case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: - if (res != SPV_REFLECT_RESULT_SUCCESS) { - p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_FAILED; - } - else { - p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_DONE; - } + case SpvOpIEqual: + DO_BINARY_UINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, == , res, CLEANUP) break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: - if (res != SPV_REFLECT_RESULT_SUCCESS) { - p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED; - } + case SpvOpINotEqual: + DO_BINARY_UINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, != , res, CLEANUP) break; - case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: - if (res != SPV_REFLECT_RESULT_SUCCESS) { - p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED; - } - else { - p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_PENDING; - } + case SpvOpULessThan: + DO_BINARY_UINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, < , res, CLEANUP) + break; + case SpvOpSLessThan: + DO_BINARY_SINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, < , res, CLEANUP) + break; + case SpvOpUGreaterThan: + DO_BINARY_UINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, > , res, CLEANUP) + break; + case SpvOpSGreaterThan: + DO_BINARY_SINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, > , res, CLEANUP) + break; + case SpvOpULessThanEqual: + DO_BINARY_UINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, <= , res, CLEANUP) + break; + case SpvOpSLessThanEqual: + DO_BINARY_SINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, <= , res, CLEANUP) + break; + case SpvOpUGreaterThanEqual: + DO_BINARY_UINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, >= , res, CLEANUP) + break; + case SpvOpSGreaterThanEqual: + DO_BINARY_SINTEGER_LOGICAL_OPERATION(evaluation_mode, p_parser, p_eval, p_node, >= , res, CLEANUP) break; - } - return res; + // check shader capability... vulkan should assume this... + case SpvOpQuantizeToF16: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + break; + + // check kernel capability... vulkan have none currently... + case SpvOpConvertFToS: case SpvOpConvertSToF: + case SpvOpConvertFToU: case SpvOpConvertUToF: + case SpvOpConvertPtrToU: case SpvOpConvertUToPtr: + case SpvOpGenericCastToPtr: case SpvOpPtrCastToGeneric: + case SpvOpBitcast: case SpvOpFNegate: + case SpvOpFAdd: case SpvOpFSub: case SpvOpFMul: case SpvOpFDiv: + case SpvOpFRem: case SpvOpFMod: + case SpvOpAccessChain: case SpvOpInBoundsAccessChain: + case SpvOpPtrAccessChain: case SpvOpInBoundsPtrAccessChain: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + break; + } + } + break; + } + CLEANUP: + switch (evaluation_mode) { + default: + res = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED; + case SPIRV_REFLECT_EVALUATION_MODE_NORMAL: + if (res != SPV_REFLECT_RESULT_SUCCESS) { + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_FAILED; + } + else { + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_DONE; + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_1PASS: + if (res != SPV_REFLECT_RESULT_SUCCESS) { + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED; + } + break; + case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: + if (res != SPV_REFLECT_RESULT_SUCCESS) { + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED; + } + else { + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_PENDING; + } + break; + } + + return res; } From 79cbd28d3965fffa9a073b0b8b4799c135a80361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sat, 6 Aug 2022 21:45:59 +0800 Subject: [PATCH 18/44] Fix const qualifier for cpp --- spirv_reflect.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index 0481d4a1..5f895bee 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -254,11 +254,11 @@ typedef struct SpvReflectPrvEvaluationNode { uint8_t idx[SPV_REFLECT_MAX_VECTOR_DIMS]; } vector_shuffle; struct CompositeExtract { - SpvReflectTypeDescription* src_type; + const SpvReflectTypeDescription* src_type; SpvReflectValueData* src_data; } composite_extract; struct CompositeInsert { - SpvReflectTypeDescription* dst_type; + const SpvReflectTypeDescription* dst_type; SpvReflectValueData* dst_data; }composite_insert; } instruction_private; @@ -6890,7 +6890,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect { EVALUATE_OPERAND(p_node->id_operands[0], res, CLEANUP) SpvReflectValueData* current_data = p_node->instruction_private.composite_extract.src_data; - SpvReflectTypeDescription* current_type = p_node->instruction_private.composite_extract.src_type; + const SpvReflectTypeDescription* current_type = p_node->instruction_private.composite_extract.src_type; res = CopyValueData(current_type, &result->data, current_data); if (res != SPV_REFLECT_RESULT_SUCCESS) { goto CLEANUP; @@ -6930,7 +6930,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; SpvReflectValueData* current_data = &p_node->id_operands[0]->value.data; - SpvReflectTypeDescription* current_type = p_node->id_operands[0]->value.type; + const SpvReflectTypeDescription* current_type = p_node->id_operands[0]->value.type; for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { uint32_t member_index; EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 5 + i, member_index, res, CLEANUP); @@ -7019,7 +7019,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect } SpvReflectPrvNode* p_parser_node = p_node->instruction_private.uninitialized; SpvReflectValueData* current_data = &result->data; - SpvReflectTypeDescription* current_type = result->type; + const SpvReflectTypeDescription* current_type = result->type; for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { uint32_t member_index; EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 6 + i, member_index, res, CLEANUP); From bb0c173f88cbb9ef1ae22a24ce6d236b1415efeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sat, 6 Aug 2022 22:22:43 +0800 Subject: [PATCH 19/44] Better WorkGroupSize builtin support One result id may be decorated with multiple builtin decoration. Deal with known builtin separately. --- spirv_reflect.c | 44 +++++++++++++++++++++++++++++--------------- spirv_reflect.h | 7 ++++++- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index 5f895bee..6021f7be 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -1415,7 +1415,8 @@ static SpvReflectResult ParseNames(SpvReflectPrvParser* p_parser) return SPV_REFLECT_RESULT_SUCCESS; } -static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser) +// builtin parsing should be done with shader module (if global) or entry point (if local) +static SpvReflectResult ParseDecorations(SpvReflectShaderModule* p_module, SpvReflectPrvParser* p_parser) { for (uint32_t i = 0; i < p_parser->node_count; ++i) { SpvReflectPrvNode* p_node = &(p_parser->nodes[i]); @@ -1540,7 +1541,17 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser) p_target_decorations->is_built_in = true; uint32_t word_offset = p_node->word_offset + member_offset + 3; // no rule specifies a result cannot be decorated twice. But let's assume this for now... - CHECKED_READU32_CAST(p_parser, word_offset, SpvBuiltIn, p_target_decorations->built_in); + SpvBuiltIn builtin_id; + CHECKED_READU32_CAST(p_parser, word_offset, SpvBuiltIn, builtin_id); + p_target_decorations->built_in = builtin_id; + // deal with known builtin here... + if (builtin_id == SpvBuiltInWorkgroupSize) { + // two result_id decorated with same global builtin, wrong decoration.. + if (p_module->_internal->builtin_WorkGroupSize != INVALID_VALUE) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + } + p_module->_internal->builtin_WorkGroupSize = target_id; + } } break; @@ -3589,22 +3600,24 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; } + // deal with WorkGroupSize builtin + if (p_module->_internal->builtin_WorkGroupSize != INVALID_VALUE) { + SpvReflectPrvNode* p_node = FindNode(p_parser, p_module->_internal->builtin_WorkGroupSize); + for (uint32_t j = 0; j < p_module->entry_point_count; ++j) { + if (p_module->entry_points[j].spirv_execution_model == SpvExecutionModelKernel || + p_module->entry_points[j].spirv_execution_model == SpvExecutionModelGLCompute) { + p_module->entry_points[j].local_size.flags = 4; + p_module->entry_points[j].local_size.x = p_node->result_id; + } + } + } + uint32_t index = 0; for (size_t i = 0; i < p_parser->node_count; ++i) { + SpvReflectPrvNode* p_node = &(p_parser->nodes[i]); - // check first if it's WorkGroupSize builtin - // maybe handling builtin as global map may be better. - if (p_node->decorations.built_in == SpvBuiltInWorkgroupSize) { - // WorkGroupSize builtin's target is all ExecutionMode instructions. - for(uint32_t j = 0; jentry_point_count; ++j) { - if(p_module->entry_points[j].spirv_execution_model == SpvExecutionModelKernel|| - p_module->entry_points[j].spirv_execution_model == SpvExecutionModelGLCompute){ - p_module->entry_points[j].local_size.flags = 4; - p_module->entry_points[j].local_size.x = p_node->result_id; - } - } - } + // Specconstants with no id means constant switch(p_node->op) { default: continue; @@ -4031,6 +4044,7 @@ static SpvReflectResult CreateShaderModule( if (IsNull(p_module->_internal)) { return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; } + p_module->_internal->builtin_WorkGroupSize = (uint32_t)INVALID_VALUE; // Copy flags p_module->_internal->module_flags = flags; // Figure out if we need to copy the SPIR-V code or not @@ -4094,7 +4108,7 @@ static SpvReflectResult CreateShaderModule( SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseDecorations(&parser); + result = ParseDecorations(p_module, &parser); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } diff --git a/spirv_reflect.h b/spirv_reflect.h index c745f7bf..2ac5606a 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -581,7 +581,12 @@ typedef struct SpvReflectShaderModule { size_t type_description_count; SpvReflectTypeDescription* type_descriptions; - SpvReflectEvaluation* evaluator; + + // variables can have multiple decoration, decorated to be + // multiple builtins. Put used builtin here for safety + // stored as result id + uint32_t builtin_WorkGroupSize; + SpvReflectEvaluation* evaluator; } * _internal; } SpvReflectShaderModule; From 46034ae7ee03523c2ca95651d66b496341f9fc70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sat, 6 Aug 2022 22:29:12 +0800 Subject: [PATCH 20/44] Remove writing literal words in insert and extract --- spirv_reflect.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index 6021f7be..81a4e9ee 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -3717,14 +3717,17 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars id_operands += p_ev_node->num_id_operands; } } - - p_eval->id_operand_buffer = (SpvReflectPrvEvaluationNode**)malloc(id_operands *sizeof(SpvReflectPrvEvaluationNode*)); - if(IsNull(p_eval->id_operand_buffer)){ - return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; + if (id_operands) { + p_eval->id_operand_buffer = (SpvReflectPrvEvaluationNode**)malloc(id_operands * sizeof(SpvReflectPrvEvaluationNode*)); + if (IsNull(p_eval->id_operand_buffer)) { + return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; + } } - p_eval->literal_word_buffer = (uint32_t*)malloc(literal_words * sizeof(uint32_t)); - if(IsNull(p_eval->literal_word_buffer)){ - return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; + if (literal_words) { + p_eval->literal_word_buffer = (uint32_t*)malloc(literal_words * sizeof(uint32_t)); + if (IsNull(p_eval->literal_word_buffer)) { + return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; + } } uint32_t id_offset = 0; uint32_t literal_offset = 0; @@ -6930,7 +6933,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect goto CLEANUP; } p_node->num_id_operands = 1; - p_node->num_literal_words = p_parser_node->word_count - 5; + p_node->num_literal_words = 0; } break; case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: @@ -6948,7 +6951,6 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { uint32_t member_index; EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 5 + i, member_index, res, CLEANUP); - p_node->literal_words[i] = member_index; res = GetMemberByIndex(p_eval->member_type_finder, current_data, current_type, member_index, ¤t_data, ¤t_type); if (res != SPV_REFLECT_RESULT_SUCCESS) { goto CLEANUP; @@ -7008,7 +7010,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect goto CLEANUP; } p_node->num_id_operands = 2; - p_node->num_literal_words = p_parser_node->word_count - 6; + p_node->num_literal_words = 0; } break; case SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS: @@ -7037,7 +7039,6 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect for (uint32_t i = 0; i < p_node->num_literal_words; ++i) { uint32_t member_index; EVAL_CHECKED_READU32(p_parser, p_parser_node->word_offset + 6 + i, member_index, res, CLEANUP); - p_node->literal_words[i] = member_index; res = GetMemberByIndex(p_eval->member_type_finder, current_data, current_type, member_index, ¤t_data, ¤t_type); if (res != SPV_REFLECT_RESULT_SUCCESS) { goto CLEANUP; From c5f79c88fe41e74cb59a15010df46b7c10de1bd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sat, 6 Aug 2022 22:30:29 +0800 Subject: [PATCH 21/44] Remove patch file --- spec_constant.patch | 302 -------------------------------------------- 1 file changed, 302 deletions(-) delete mode 100644 spec_constant.patch diff --git a/spec_constant.patch b/spec_constant.patch deleted file mode 100644 index c76662d8..00000000 --- a/spec_constant.patch +++ /dev/null @@ -1,302 +0,0 @@ -diff --git a/thirdparty/spirv-reflect/spirv_reflect.c b/thirdparty/spirv-reflect/spirv_reflect.c -index e9b11bf495..f181df5fa2 100644 ---- a/thirdparty/spirv-reflect/spirv_reflect.c -+++ b/thirdparty/spirv-reflect/spirv_reflect.c -@@ -125,6 +125,9 @@ typedef struct SpvReflectPrvDecorations { - SpvReflectPrvNumberDecoration location; - SpvReflectPrvNumberDecoration offset; - SpvReflectPrvNumberDecoration uav_counter_buffer; -+// -- GODOT begin -- -+ SpvReflectPrvNumberDecoration specialization_constant; -+// -- GODOT end -- - SpvReflectPrvStringDecoration semantic; - uint32_t array_stride; - uint32_t matrix_stride; -@@ -631,6 +634,9 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) - p_parser->nodes[i].decorations.offset.value = (uint32_t)INVALID_VALUE; - p_parser->nodes[i].decorations.uav_counter_buffer.value = (uint32_t)INVALID_VALUE; - p_parser->nodes[i].decorations.built_in = (SpvBuiltIn)INVALID_VALUE; -+// -- GODOT begin -- -+ p_parser->nodes[i].decorations.specialization_constant.value = (SpvBuiltIn)INVALID_VALUE; -+// -- GODOT end -- - } - // Mark source file id node - p_parser->source_file_id = (uint32_t)INVALID_VALUE; -@@ -821,10 +827,16 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) - CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id); - } - break; -- -+// -- GODOT begin -- - case SpvOpSpecConstantTrue: - case SpvOpSpecConstantFalse: -- case SpvOpSpecConstant: -+ case SpvOpSpecConstant: { -+ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id); -+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id); -+ p_node->is_type = true; -+ } -+ break; -+// -- GODOT end -- - case SpvOpSpecConstantComposite: - case SpvOpSpecConstantOp: { - CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id); -@@ -856,7 +868,7 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) - CHECKED_READU32(p_parser, p_node->word_offset + 3, p_access_chain->base_id); - // - // SPIRV_ACCESS_CHAIN_INDEX_OFFSET (4) is the number of words up until the first index: -- // [Node, Result Type Id, Result Id, Base Id, ] -+ // [SpvReflectPrvNode, Result Type Id, Result Id, Base Id, ] - // - p_access_chain->index_count = (node_word_count - SPIRV_ACCESS_CHAIN_INDEX_OFFSET); - if (p_access_chain->index_count > 0) { -@@ -1338,6 +1350,9 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser) - skip = true; - } - break; -+// -- GODOT begin -- -+ case SpvDecorationSpecId: -+// -- GODOT end -- - case SpvDecorationRelaxedPrecision: - case SpvDecorationBlock: - case SpvDecorationBufferBlock: -@@ -1481,7 +1496,14 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser) - p_target_decorations->input_attachment_index.word_offset = word_offset; - } - break; -- -+// -- GODOT begin -- -+ case SpvDecorationSpecId: { -+ uint32_t word_offset = p_node->word_offset + member_offset+ 3; -+ CHECKED_READU32(p_parser, word_offset, p_target_decorations->specialization_constant.value); -+ p_target_decorations->specialization_constant.word_offset = word_offset; -+ } -+ break; -+// -- GODOT end -- - case SpvReflectDecorationHlslCounterBufferGOOGLE: { - uint32_t word_offset = p_node->word_offset + member_offset+ 3; - CHECKED_READU32(p_parser, word_offset, p_target_decorations->uav_counter_buffer.value); -@@ -1789,6 +1811,13 @@ static SpvReflectResult ParseType( - p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_ACCELERATION_STRUCTURE; - } - break; -+// -- GODOT begin -- -+ case SpvOpSpecConstantTrue: -+ case SpvOpSpecConstantFalse: -+ case SpvOpSpecConstant: { -+ } -+ break; -+// -- GODOT end -- - } - - if (result == SPV_REFLECT_RESULT_SUCCESS) { -@@ -3269,6 +3298,69 @@ static SpvReflectResult ParseExecutionModes( - return SPV_REFLECT_RESULT_SUCCESS; - } - -+// -- GODOT begin -- -+static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) -+{ -+ p_module->specialization_constant_count = 0; -+ p_module->specialization_constants = NULL; -+ for (size_t i = 0; i < p_parser->node_count; ++i) { -+ SpvReflectPrvNode* p_node = &(p_parser->nodes[i]); -+ if (p_node->op == SpvOpSpecConstantTrue || p_node->op == SpvOpSpecConstantFalse || p_node->op == SpvOpSpecConstant) { -+ p_module->specialization_constant_count++; -+ } -+ } -+ -+ if (p_module->specialization_constant_count == 0) { -+ return SPV_REFLECT_RESULT_SUCCESS; -+ } -+ -+ p_module->specialization_constants = (SpvReflectSpecializationConstant*)calloc(p_module->specialization_constant_count, sizeof(SpvReflectSpecializationConstant)); -+ -+ uint32_t index = 0; -+ -+ for (size_t i = 0; i < p_parser->node_count; ++i) { -+ SpvReflectPrvNode* p_node = &(p_parser->nodes[i]); -+ switch(p_node->op) { -+ default: continue; -+ case SpvOpSpecConstantTrue: { -+ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL; -+ p_module->specialization_constants[index].default_value.int_bool_value = 1; -+ } break; -+ case SpvOpSpecConstantFalse: { -+ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL; -+ p_module->specialization_constants[index].default_value.int_bool_value = 0; -+ } break; -+ case SpvOpSpecConstant: { -+ SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS; -+ uint32_t element_type_id = (uint32_t)INVALID_VALUE; -+ uint32_t default_value = 0; -+ IF_READU32(result, p_parser, p_node->word_offset + 1, element_type_id); -+ IF_READU32(result, p_parser, p_node->word_offset + 3, default_value); -+ -+ SpvReflectPrvNode* p_next_node = FindNode(p_parser, element_type_id); -+ -+ if (p_next_node->op == SpvOpTypeInt) { -+ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_INT; -+ } else if (p_next_node->op == SpvOpTypeFloat) { -+ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT; -+ } else { -+ return SPV_REFLECT_RESULT_ERROR_PARSE_FAILED; -+ } -+ -+ p_module->specialization_constants[index].default_value.int_bool_value = default_value; //bits are the same for int and float -+ } break; -+ } -+ -+ p_module->specialization_constants[index].name = p_node->name; -+ p_module->specialization_constants[index].constant_id = p_node->decorations.specialization_constant.value; -+ p_module->specialization_constants[index].spirv_id = p_node->result_id; -+ index++; -+ } -+ -+ return SPV_REFLECT_RESULT_SUCCESS; -+} -+// -- GODOT end -- -+ - static SpvReflectResult ParsePushConstantBlocks( - SpvReflectPrvParser* p_parser, - SpvReflectShaderModule* p_module) -@@ -3650,6 +3742,12 @@ static SpvReflectResult CreateShaderModule( - result = ParsePushConstantBlocks(&parser, p_module); - SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); - } -+// -- GODOT begin -- -+ if (result == SPV_REFLECT_RESULT_SUCCESS) { -+ result = ParseSpecializationConstants(&parser, p_module); -+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); -+ } -+// -- GODOT end -- - if (result == SPV_REFLECT_RESULT_SUCCESS) { - result = ParseEntryPoints(&parser, p_module); - SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); -@@ -3807,6 +3905,9 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module) - SafeFree(p_entry->used_push_constants); - } - SafeFree(p_module->entry_points); -+// -- GODOT begin -- -+ SafeFree(p_module->specialization_constants); -+// -- GODOT end -- - - // Push constants - for (size_t i = 0; i < p_module->push_constant_block_count; ++i) { -@@ -4077,6 +4178,38 @@ SpvReflectResult spvReflectEnumerateEntryPointInterfaceVariables( - return SPV_REFLECT_RESULT_SUCCESS; - } - -+// -- GODOT begin -- -+SpvReflectResult spvReflectEnumerateSpecializationConstants( -+ const SpvReflectShaderModule* p_module, -+ uint32_t* p_count, -+ SpvReflectSpecializationConstant** pp_constants -+) -+{ -+ if (IsNull(p_module)) { -+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; -+ } -+ if (IsNull(p_count)) { -+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; -+ } -+ -+ if (IsNotNull(pp_constants)) { -+ if (*p_count != p_module->specialization_constant_count) { -+ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH; -+ } -+ -+ for (uint32_t index = 0; index < *p_count; ++index) { -+ SpvReflectSpecializationConstant *p_const = &p_module->specialization_constants[index]; -+ pp_constants[index] = p_const; -+ } -+ } -+ else { -+ *p_count = p_module->specialization_constant_count; -+ } -+ -+ return SPV_REFLECT_RESULT_SUCCESS; -+} -+// -- GODOT end -- -+ - SpvReflectResult spvReflectEnumerateInputVariables( - const SpvReflectShaderModule* p_module, - uint32_t* p_count, -diff --git a/thirdparty/spirv-reflect/spirv_reflect.h b/thirdparty/spirv-reflect/spirv_reflect.h -index e9e4c40755..948533d3c0 100644 ---- a/thirdparty/spirv-reflect/spirv_reflect.h -+++ b/thirdparty/spirv-reflect/spirv_reflect.h -@@ -323,6 +323,28 @@ typedef struct SpvReflectTypeDescription { - struct SpvReflectTypeDescription* members; - } SpvReflectTypeDescription; - -+// -- GODOT begin -- -+/*! @struct SpvReflectSpecializationConstant -+ -+*/ -+ -+typedef enum SpvReflectSpecializationConstantType { -+ SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL = 0, -+ SPV_REFLECT_SPECIALIZATION_CONSTANT_INT = 1, -+ SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT = 2, -+} SpvReflectSpecializationConstantType; -+ -+typedef struct SpvReflectSpecializationConstant { -+ const char* name; -+ uint32_t spirv_id; -+ uint32_t constant_id; -+ SpvReflectSpecializationConstantType constant_type; -+ union { -+ float float_value; -+ uint32_t int_bool_value; -+ } default_value; -+} SpvReflectSpecializationConstant; -+// -- GODOT end -- - - /*! @struct SpvReflectInterfaceVariable - -@@ -472,6 +494,10 @@ typedef struct SpvReflectShaderModule { - SpvReflectInterfaceVariable* interface_variables; // Uses value(s) from first entry point - uint32_t push_constant_block_count; // Uses value(s) from first entry point - SpvReflectBlockVariable* push_constant_blocks; // Uses value(s) from first entry point -+ // -- GODOT begin -- -+ uint32_t specialization_constant_count; -+ SpvReflectSpecializationConstant* specialization_constants; -+ // -- GODOT end -- - - struct Internal { - SpvReflectModuleFlags module_flags; -@@ -744,6 +770,33 @@ SpvReflectResult spvReflectEnumerateInputVariables( - SpvReflectInterfaceVariable** pp_variables - ); - -+// -- GOODT begin -- -+/*! @fn spvReflectEnumerateSpecializationConstants -+ @brief If the module contains multiple entry points, this will only get -+ the specialization constants for the first one. -+ @param p_module Pointer to an instance of SpvReflectShaderModule. -+ @param p_count If pp_constants is NULL, the module's specialization constant -+ count will be stored here. -+ If pp_variables is not NULL, *p_count must contain -+ the module's specialization constant count. -+ @param pp_variables If NULL, the module's specialization constant count will be -+ written to *p_count. -+ If non-NULL, pp_constants must point to an array with -+ *p_count entries, where pointers to the module's -+ specialization constants will be written. The caller must not -+ free the specialization constants written to this array. -+ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS. -+ Otherwise, the error code indicates the cause of the -+ failure. -+ -+*/ -+SpvReflectResult spvReflectEnumerateSpecializationConstants( -+ const SpvReflectShaderModule* p_module, -+ uint32_t* p_count, -+ SpvReflectSpecializationConstant** pp_constants -+); -+// -- GODOT end -- -+ - /*! @fn spvReflectEnumerateEntryPointInputVariables - @brief Enumerate the input variables for a given entry point. - @param entry_point The name of the entry point to get the input variables for. \ No newline at end of file From 60a2614bdbab1489ceeab5bacb21bfedaf2ecf38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sat, 6 Aug 2022 22:53:08 +0800 Subject: [PATCH 22/44] Make evaluation support optional --- spirv_reflect.c | 33 +++++++++++++++++++++++++++++++-- spirv_reflect.h | 25 +++++++++++++++++++++---- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index 81a4e9ee..7113db42 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -3546,6 +3546,7 @@ static SpvReflectResult ParserGetScalarConstant(const SpvReflectShaderModule* p_ || ((op_code) == SpvOpConstantPipeStorage) || ((op_code) == SpvOpSpecConstantCompositeContinuedINTEL)\ || ((op_code) == SpvOpConstantFunctionPointerINTEL) || ((op_code) == SpvOpConstantCompositeContinuedINTEL)) +#if SPIRV_REFLECT_ENABLE_CONSTANT_EVALUATION #ifdef _MSC_VER #define SPIRV_REFLECT_FORCEINLINE __forceinline #else @@ -3572,6 +3573,8 @@ static SpvReflectResult EvaluateResult_2PASS(SpvReflectEvaluation* p_eval, SpvRe return EvaluateResult_Impl(p_eval, p_node, SPIRV_REFLECT_EVALUATION_MODE_AST_2PASS, p_parser); } +#endif + static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) { p_module->specialization_constant_count = 0; @@ -3649,7 +3652,7 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars p_module->specialization_constants[index].spirv_id = p_node->result_id; index++; } - +#if SPIRV_REFLECT_ENABLE_CONSTANT_EVALUATION // need to evaluate expr later on... if (p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT) { p_module->_internal->evaluator = (SpvReflectEvaluation*)calloc(1, sizeof(SpvReflectEvaluation)); @@ -3750,7 +3753,7 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars } } } - +#endif return SPV_REFLECT_RESULT_SUCCESS; } @@ -4340,8 +4343,10 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module) SafeFree(p_module->specialization_constants); if (p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT) { + if(p_module->_internal->evaluator) { DestroyEvaluator(p_module->_internal->evaluator); SafeFree(p_module->_internal->evaluator) + } } // Free internal @@ -5570,6 +5575,8 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect } } +#if SPIRV_REFLECT_ENABLE_CONSTANT_EVALUATION + #define CHECK_INSTRUCTION_SIZE(node, expected) \ { \ if (node->word_count != expected) { \ @@ -7422,6 +7429,28 @@ int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id } return HaveNodeInTree(p_node, p_spec, false); } +#else +SpvReflectEvaluation* spvReflectGetEvaluationInterface(SpvReflectShaderModule* p_module) +{ + (void)p_module; + return NULL; +} + +SpvReflectResult spvReflectEvaluateResult(SpvReflectEvaluation* p_eval, uint32_t result_id, const SpvReflectValue** result) +{ + (void)p_eval; + (void)result_id; + (void)result; + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; +} +int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id, uint32_t specId) +{ + (void)p_eval; + (void)result_id; + (void)specId; + return 0; +} +#endif diff --git a/spirv_reflect.h b/spirv_reflect.h index 2ac5606a..d7faf1e7 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -537,11 +537,13 @@ typedef struct SpvReflectEntryPoint { uint32_t output_vertices; // valid for geometry, tesselation } SpvReflectEntryPoint; + /*! @struct SpvReflectEvaluation @brief Opaque type that stores evaluation state and information */ typedef struct SpvReflectEvaluation SpvReflectEvaluation; + /*! @struct SpvReflectShaderModule */ @@ -1570,6 +1572,16 @@ typedef enum SpvReflectScalarType { Otherwise, the error code indicates the cause of the failure. */ +/*! @fn spvReflectSetSpecConstantValue +@brief Sets the current value of specialization constant. Type must follow c/c++ type aliasing rules. +@param p_eval Pointer to an instance of SpvReflectEvaluation. +@param specId Specialization constant id of the constant. +@param type Type of user specified value. For error checking. +@param value User provided value. +@return If successful, returns SPV_REFLECT_RESULT_SUCCESS. +Otherwise, the error code indicates the cause of +the failure. +*/ SpvReflectResult spvReflectSetSpecConstantValue(SpvReflectEvaluation* p_eval, uint32_t specId, SpvReflectScalarType type, const SpvReflectScalarValueData* value); /*! @fn spvReflectGetSpecConstantValue @@ -1581,6 +1593,15 @@ SpvReflectResult spvReflectSetSpecConstantValue(SpvReflectEvaluation* p_eval, ui Otherwise, the error code indicates the cause of the failure. */ +/*! @fn spvReflectGetSpecConstantValue +@brief Get the current value of specialization constant. Type must follow c/c++ type aliasing rules. +@param p_eval Pointer to an instance of SpvReflectEvaluation. +@param specId Specialization constant id of the constant. +@param value Current value. +@return If successful, returns SPV_REFLECT_RESULT_SUCCESS. +Otherwise, the error code indicates the cause of +the failure. +*/ SpvReflectResult spvReflectGetSpecConstantValue(SpvReflectEvaluation* p_eval, uint32_t specId, const SpvReflectValue** value); /*! @fn spvReflectEvaluateResult @@ -1610,9 +1631,6 @@ SpvReflectResult spvReflectEvaluateResult(SpvReflectEvaluation* p_eval, uint32_t */ int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id, uint32_t specId); -/* - -*/ #if defined(__cplusplus) }; @@ -1719,7 +1737,6 @@ class ShaderModule { SpvReflectResult ChangeDescriptorSetNumber(const SpvReflectDescriptorSet* p_set, uint32_t new_set_number = SPV_REFLECT_SET_NUMBER_DONT_CHANGE); SpvReflectResult ChangeInputVariableLocation(const SpvReflectInterfaceVariable* p_input_variable, uint32_t new_location); SpvReflectResult ChangeOutputVariableLocation(const SpvReflectInterfaceVariable* p_output_variable, uint32_t new_location); - SpvReflectResult EvaluateResult(uint32_t result_id, const SpvReflectValue** result) { if (p_eval) { From 967e211d778200ec3cf5cab8663885ff1f225dd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sat, 6 Aug 2022 23:09:47 +0800 Subject: [PATCH 23/44] Add cmake option Also let static lib respect the assert option... Also change asserts to respect assert option. --- CMakeLists.txt | 20 ++++++++++++- spirv_reflect.c | 76 ++++++++++++++++++++++++------------------------- 2 files changed, 57 insertions(+), 39 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ecc0668b..8f96f275 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ OPTION(SPIRV_REFLECT_STRIPPER "Build stripper utility" OFF) OPTION(SPIRV_REFLECT_STATIC_LIB "Build a SPIRV-Reflect static library" OFF) OPTION(SPIRV_REFLECT_BUILD_TESTS "Build the SPIRV-Reflect test suite" OFF) OPTION(SPIRV_REFLECT_ENABLE_ASSERTS "Enable asserts for debugging" OFF) +OPTION(SPIRV_REFLECT_ENABLE_EVALUATION "Enable evaluating constants' result id" ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON) set(CMAKE_CXX_STANDARD 14) @@ -35,6 +36,9 @@ if (SPIRV_REFLECT_EXECUTABLE) if (SPIRV_REFLECT_ENABLE_ASSERTS) target_compile_definitions(spirv-reflect PRIVATE SPIRV_REFLECT_ENABLE_ASSERTS) endif() + if(SPIRV_REFLECT_ENABLE_EVALUATION) + target_compile_definitions(spirv-reflect PRIVATE SPIRV_REFLECT_ENABLE_CONSTANT_EVALUATION=1) + endif() set_target_properties(spirv-reflect PROPERTIES CXX_STANDARD 11) target_include_directories(spirv-reflect PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) if(WIN32) @@ -63,6 +67,9 @@ if (SPIRV_REFLECT_EXECUTABLE) if (SPIRV_REFLECT_ENABLE_ASSERTS) target_compile_definitions(spirv-reflect-pp PRIVATE SPIRV_REFLECT_ENABLE_ASSERTS) endif() + if(SPIRV_REFLECT_ENABLE_EVALUATION) + target_compile_definitions(spirv-reflect-pp PRIVATE SPIRV_REFLECT_ENABLE_CONSTANT_EVALUATION=1) + endif() set_target_properties(spirv-reflect-pp PROPERTIES CXX_STANDARD 11) target_include_directories(spirv-reflect-pp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) if(WIN32) @@ -98,6 +105,12 @@ if (SPIRV_REFLECT_BUILD_TESTS) CXX_STANDARD 11) target_compile_definitions(test-spirv-reflect PRIVATE $<$:_CRT_SECURE_NO_WARNINGS>) + if (SPIRV_REFLECT_ENABLE_ASSERTS) + target_compile_definitions(test-spirv-reflect PRIVATE SPIRV_REFLECT_ENABLE_ASSERTS) + endif() + if(SPIRV_REFLECT_ENABLE_EVALUATION) + target_compile_definitions(test-spirv-reflect PRIVATE SPIRV_REFLECT_ENABLE_CONSTANT_EVALUATION=1) + endif() target_link_libraries(test-spirv-reflect gtest_main) target_include_directories(test-spirv-reflect PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) add_custom_command(TARGET test-spirv-reflect POST_BUILD @@ -108,7 +121,12 @@ endif() if(SPIRV_REFLECT_STATIC_LIB) add_library(spirv-reflect-static STATIC ${CMAKE_CURRENT_SOURCE_DIR}/spirv_reflect.h ${CMAKE_CURRENT_SOURCE_DIR}/spirv_reflect.c) - + if (SPIRV_REFLECT_ENABLE_ASSERTS) + target_compile_definitions(spirv-reflect-static PRIVATE SPIRV_REFLECT_ENABLE_ASSERTS) + endif() + if(SPIRV_REFLECT_ENABLE_EVALUATION) + target_compile_definitions(spirv-reflect-static PRIVATE SPIRV_REFLECT_ENABLE_CONSTANT_EVALUATION=1) + endif() target_include_directories(spirv-reflect-static PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) install(TARGETS spirv-reflect-static LIBRARY DESTINATION lib) diff --git a/spirv_reflect.c b/spirv_reflect.c index 7113db42..db9561b4 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -297,7 +297,7 @@ static uint32_t RoundUp( uint32_t value, uint32_t multiple) { - assert(multiple && ((multiple & (multiple - 1)) == 0)); + SPV_REFLECT_ASSERT(multiple && ((multiple & (multiple - 1)) == 0)); return (value + multiple - 1) & ~(multiple - 1); } @@ -437,9 +437,9 @@ static SpvReflectResult ReadU32( uint32_t word_offset, uint32_t* p_value) { - assert(IsNotNull(p_parser)); - assert(IsNotNull(p_parser->spirv_code)); - assert(InRange(p_parser, word_offset)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser->spirv_code)); + SPV_REFLECT_ASSERT(InRange(p_parser, word_offset)); SpvReflectResult result = SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_EOF; if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && InRange(p_parser, word_offset)) { *p_value = *(p_parser->spirv_code + word_offset); @@ -493,9 +493,9 @@ static SpvReflectResult ReadStr( ) { uint32_t limit = (word_offset + word_count); - assert(IsNotNull(p_parser)); - assert(IsNotNull(p_parser->spirv_code)); - assert(InRange(p_parser, limit)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser->spirv_code)); + SPV_REFLECT_ASSERT(InRange(p_parser, limit)); SpvReflectResult result = SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_EOF; if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && InRange(p_parser, limit)) { const char* c_str = (const char*)(p_parser->spirv_code + word_offset + word_index); @@ -697,8 +697,8 @@ static void DestroyParser(SpvReflectPrvParser* p_parser) static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) { - assert(IsNotNull(p_parser)); - assert(IsNotNull(p_parser->spirv_code)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser->spirv_code)); uint32_t* p_spirv = p_parser->spirv_code; uint32_t spirv_word_index = SPIRV_STARTING_WORD_INDEX; @@ -979,7 +979,7 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) // Read index value uint32_t index_value = UINT32_MAX; CHECKED_READU32(p_parser, p_index_value_node->word_offset + 3, index_value); - assert(index_value != UINT32_MAX); + SPV_REFLECT_ASSERT(index_value != UINT32_MAX); // Write index value to array p_access_chain->indexes[index_index] = index_value; } @@ -1029,9 +1029,9 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) static SpvReflectResult ParseStrings(SpvReflectPrvParser* p_parser) { - assert(IsNotNull(p_parser)); - assert(IsNotNull(p_parser->spirv_code)); - assert(IsNotNull(p_parser->nodes)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser->spirv_code)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser->nodes)); // Early out if (p_parser->string_count == 0) { @@ -1052,7 +1052,7 @@ static SpvReflectResult ParseStrings(SpvReflectPrvParser* p_parser) } // Paranoid check against string count - assert(string_index < p_parser->string_count); + SPV_REFLECT_ASSERT(string_index < p_parser->string_count); if (string_index >= p_parser->string_count) { return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH; } @@ -1075,8 +1075,8 @@ static SpvReflectResult ParseStrings(SpvReflectPrvParser* p_parser) static SpvReflectResult ParseSource(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) { - assert(IsNotNull(p_parser)); - assert(IsNotNull(p_parser->spirv_code)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser->spirv_code)); if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code)) { // Source file @@ -1251,9 +1251,9 @@ static int SortCompareFunctions( static SpvReflectResult ParseFunctions(SpvReflectPrvParser* p_parser) { - assert(IsNotNull(p_parser)); - assert(IsNotNull(p_parser->spirv_code)); - assert(IsNotNull(p_parser->nodes)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser->spirv_code)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser->nodes)); if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) { if (p_parser->function_count == 0) { @@ -1333,9 +1333,9 @@ static SpvReflectResult ParseFunctions(SpvReflectPrvParser* p_parser) static SpvReflectResult ParseMemberCounts(SpvReflectPrvParser* p_parser) { - assert(IsNotNull(p_parser)); - assert(IsNotNull(p_parser->spirv_code)); - assert(IsNotNull(p_parser->nodes)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser->spirv_code)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser->nodes)); if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) { for (size_t i = 0; i < p_parser->node_count; ++i) { @@ -1383,9 +1383,9 @@ static SpvReflectResult ParseMemberCounts(SpvReflectPrvParser* p_parser) static SpvReflectResult ParseNames(SpvReflectPrvParser* p_parser) { - assert(IsNotNull(p_parser)); - assert(IsNotNull(p_parser->spirv_code)); - assert(IsNotNull(p_parser->nodes)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser->spirv_code)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser->nodes)); if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) { for (size_t i = 0; i < p_parser->node_count; ++i) { @@ -1895,7 +1895,7 @@ static SpvReflectResult ParseType( // Member decorations SpvReflectPrvDecorations* p_member_decorations = &p_node->member_decorations[member_index]; - assert(member_index < p_type->member_count); + SPV_REFLECT_ASSERT(member_index < p_type->member_count); // Parse member type SpvReflectTypeDescription* p_member_type = &(p_type->members[member_index]); p_member_type->id = member_id; @@ -1995,7 +1995,7 @@ static int SortCompareDescriptorBinding(const void* a, const void* b) if (value == 0) { // use spirv-id as a tiebreaker to ensure a stable ordering, as they're guaranteed // unique. - assert(p_elem_a->spirv_id != p_elem_b->spirv_id); + SPV_REFLECT_ASSERT(p_elem_a->spirv_id != p_elem_b->spirv_id); value = (int)(p_elem_a->spirv_id) - (int)(p_elem_b->spirv_id); } return value; @@ -2153,12 +2153,12 @@ static SpvReflectResult ParseDescriptorType(SpvReflectShaderModule* p_module) if ((int)p_descriptor->descriptor_type == (int)INVALID_VALUE) { switch (p_type->type_flags & SPV_REFLECT_TYPE_FLAG_EXTERNAL_MASK) { - default: assert(false && "unknown type flag"); break; + default: SPV_REFLECT_ASSERT(false && "unknown type flag"); break; case SPV_REFLECT_TYPE_FLAG_EXTERNAL_IMAGE: { if (p_descriptor->image.dim == SpvDimBuffer) { switch (p_descriptor->image.sampled) { - default: assert(false && "unknown texel buffer sampled value"); break; + default: SPV_REFLECT_ASSERT(false && "unknown texel buffer sampled value"); break; case IMAGE_SAMPLED: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; break; case IMAGE_STORAGE: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; break; } @@ -2168,7 +2168,7 @@ static SpvReflectResult ParseDescriptorType(SpvReflectShaderModule* p_module) } else { switch (p_descriptor->image.sampled) { - default: assert(false && "unknown image sampled value"); break; + default: SPV_REFLECT_ASSERT(false && "unknown image sampled value"); break; case IMAGE_SAMPLED: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE; break; case IMAGE_STORAGE: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE; break; } @@ -2185,7 +2185,7 @@ static SpvReflectResult ParseDescriptorType(SpvReflectShaderModule* p_module) // This is a workaround for: https://github.com/KhronosGroup/glslang/issues/1096 if (p_descriptor->image.dim == SpvDimBuffer) { switch (p_descriptor->image.sampled) { - default: assert(false && "unknown texel buffer sampled value"); break; + default: SPV_REFLECT_ASSERT(false && "unknown texel buffer sampled value"); break; case IMAGE_SAMPLED: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; break; case IMAGE_STORAGE: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; break; } @@ -2204,7 +2204,7 @@ static SpvReflectResult ParseDescriptorType(SpvReflectShaderModule* p_module) p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER; } else { - assert(false && "unknown struct"); + SPV_REFLECT_ASSERT(false && "unknown struct"); } } break; @@ -2598,7 +2598,7 @@ static SpvReflectResult ParseDescriptorBlockVariableUsage( break; case SpvOpTypeStruct: { - assert(p_var->member_count > 0); + SPV_REFLECT_ASSERT(p_var->member_count > 0); if (p_var->member_count == 0) { return SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_BLOCK_DATA; } @@ -3310,9 +3310,9 @@ static SpvReflectResult ParseExecutionModes( SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) { - assert(IsNotNull(p_parser)); - assert(IsNotNull(p_parser->nodes)); - assert(IsNotNull(p_module)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser)); + SPV_REFLECT_ASSERT(IsNotNull(p_parser->nodes)); + SPV_REFLECT_ASSERT(IsNotNull(p_module)); if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) { for (size_t node_idx = 0; node_idx < p_parser->node_count; ++node_idx) { @@ -3842,7 +3842,7 @@ static int SortCompareDescriptorSet(const void* a, const void* b) int value = (int)(p_elem_a->set) - (int)(p_elem_b->set); // We should never see duplicate descriptor set numbers in a shader; if so, a tiebreaker // would be needed here. - assert(value != 0); + SPV_REFLECT_ASSERT(value != 0); return value; } @@ -3978,7 +3978,7 @@ static SpvReflectResult ParseDescriptorSets(SpvReflectShaderModule* p_module) for (uint32_t j = 0; j < p_module->descriptor_binding_count; ++j) { SpvReflectDescriptorBinding* p_descriptor = &(p_module->descriptor_bindings[j]); if (p_descriptor->set == p_set->set) { - assert(descriptor_index < p_set->binding_count); + SPV_REFLECT_ASSERT(descriptor_index < p_set->binding_count); p_set->bindings[descriptor_index] = p_descriptor; ++descriptor_index; } From b6a67f436a59a5e86302b1ae4ad7dfb7abaae6a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sat, 6 Aug 2022 23:38:43 +0800 Subject: [PATCH 24/44] Separate evaluation state from shader info in cpp Evaluation state separated from shader info. This way shader is still const, but evaluator state can be modified... (A bit hacky in GetEvaluation() const, but that doesn't violate aliasing rules.) --- common/output_stream.cpp | 40 ++++++++++++------------- common/output_stream.h | 2 +- spirv_reflect.c | 2 +- spirv_reflect.h | 65 ++++++++++++++++++++++++++++++++-------- 4 files changed, 74 insertions(+), 35 deletions(-) diff --git a/common/output_stream.cpp b/common/output_stream.cpp index 8724329e..73364864 100644 --- a/common/output_stream.cpp +++ b/common/output_stream.cpp @@ -600,7 +600,7 @@ std::string ToStringComponentType(const SpvReflectTypeDescription& type, uint32_ } void ParseBlockMembersToTextLines( - spv_reflect::ShaderModule& obj, + spv_reflect::Evaluation obj, const char* indent, int indent_depth, bool flatten_cbuffers, const std::string& parent_name, uint32_t member_count, const SpvReflectBlockVariable* p_members, std::vector* p_text_lines) { const char* t = indent; @@ -728,7 +728,7 @@ void ParseBlockMembersToTextLines( } } -void ParseBlockVariableToTextLines(spv_reflect::ShaderModule& obj, const char* indent, bool flatten_cbuffers, const SpvReflectBlockVariable& block_var, std::vector* p_text_lines) +void ParseBlockVariableToTextLines(spv_reflect::Evaluation obj, const char* indent, bool flatten_cbuffers, const SpvReflectBlockVariable& block_var, std::vector* p_text_lines) { // Begin block TextLine tl = {}; @@ -944,7 +944,7 @@ void StreamWriteTextLines(std::ostream& os, const char* indent, bool flatten_cbu } } -void StreamWritePushConstantsBlock(std::ostream& os, spv_reflect::ShaderModule& shader, const SpvReflectBlockVariable& obj, bool flatten_cbuffers, const char* indent) +void StreamWritePushConstantsBlock(std::ostream& os, spv_reflect::Evaluation eval, const SpvReflectBlockVariable& obj, bool flatten_cbuffers, const char* indent) { const char* t = indent; os << t << "spirv id : " << obj.spirv_id << "\n"; @@ -955,7 +955,7 @@ void StreamWritePushConstantsBlock(std::ostream& os, spv_reflect::ShaderModule& } std::vector text_lines; - ParseBlockVariableToTextLines(shader, " ", flatten_cbuffers, obj, &text_lines); + ParseBlockVariableToTextLines(eval, " ", flatten_cbuffers, obj, &text_lines); if (!text_lines.empty()) { os << "\n"; StreamWriteTextLines(os, t, flatten_cbuffers, text_lines); @@ -963,7 +963,7 @@ void StreamWritePushConstantsBlock(std::ostream& os, spv_reflect::ShaderModule& } } -void StreamWriteDescriptorBinding(std::ostream& os, spv_reflect::ShaderModule& shader, const SpvReflectDescriptorBinding& obj, bool write_set, bool flatten_cbuffers, const char* indent) +void StreamWriteDescriptorBinding(std::ostream& os, spv_reflect::Evaluation eval, const SpvReflectDescriptorBinding& obj, bool write_set, bool flatten_cbuffers, const char* indent) { const char* t = indent; os << t << "spirv id : " << obj.spirv_id << "\n"; @@ -1008,7 +1008,7 @@ void StreamWriteDescriptorBinding(std::ostream& os, spv_reflect::ShaderModule& s if (obj.descriptor_type == SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER || obj.descriptor_type == SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER) { std::vector text_lines; - ParseBlockVariableToTextLines(shader, " ", flatten_cbuffers, obj.block, &text_lines); + ParseBlockVariableToTextLines(eval, " ", flatten_cbuffers, obj.block, &text_lines); if (!text_lines.empty()) { os << "\n"; StreamWriteTextLines(os, t, flatten_cbuffers, text_lines); @@ -1017,7 +1017,7 @@ void StreamWriteDescriptorBinding(std::ostream& os, spv_reflect::ShaderModule& s } } -void StreamWriteInterfaceVariable(std::ostream& os, spv_reflect::ShaderModule& shader, const SpvReflectInterfaceVariable& obj, const char* indent) +void StreamWriteInterfaceVariable(std::ostream& os, spv_reflect::Evaluation eval, const SpvReflectInterfaceVariable& obj, const char* indent) { const char* t = indent; os << t << "spirv id : " << obj.spirv_id << "\n"; @@ -1039,7 +1039,7 @@ void StreamWriteInterfaceVariable(std::ostream& os, spv_reflect::ShaderModule& s uint32_t dim = obj.array.dims[dim_index]; if (dim == 0xFFFFFFFF) { const SpvReflectValue* val; - SpvReflectResult res = shader.EvaluateResult(obj.array.spec_constant_op_ids[dim_index], &val); + SpvReflectResult res = eval.EvaluateResult(obj.array.spec_constant_op_ids[dim_index], &val); if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { dim = val->data.numeric.scalar.value.uint32_bool_value; } @@ -1134,7 +1134,7 @@ void StreamWriteSpecializationConstant(std::ostream& os, const SpvReflectSpecial } } -void StreamWriteEntryPoint(std::ostream& os, spv_reflect::ShaderModule& shader, const SpvReflectEntryPoint& obj, const char* indent) +void StreamWriteEntryPoint(std::ostream& os, spv_reflect::Evaluation eval, const SpvReflectEntryPoint& obj, const char* indent) { os << indent << "entry point : " << obj.name; os << " (stage=" << ToStringShaderStage(obj.shader_stage) << ")"; @@ -1148,7 +1148,7 @@ void StreamWriteEntryPoint(std::ostream& os, spv_reflect::ShaderModule& shader, } if(obj.local_size.flags & 4) { const SpvReflectValue* val; - SpvReflectResult res = shader.EvaluateResult(obj.local_size.x, &val); + SpvReflectResult res = eval.EvaluateResult(obj.local_size.x, &val); if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == (SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_VECTOR)) && (val->type->traits.numeric.scalar.width == 32)) { os << "(" << val->data.numeric.vector.value[0].value.uint32_bool_value << ", " @@ -1162,7 +1162,7 @@ void StreamWriteEntryPoint(std::ostream& os, spv_reflect::ShaderModule& shader, else if(obj.local_size.flags & 1) { os << "("; const SpvReflectValue* val; - SpvReflectResult res = shader.EvaluateResult(obj.local_size.x, &val); + SpvReflectResult res = eval.EvaluateResult(obj.local_size.x, &val); if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { os << val->data.numeric.scalar.value.uint32_bool_value; } @@ -1170,14 +1170,14 @@ void StreamWriteEntryPoint(std::ostream& os, spv_reflect::ShaderModule& shader, os << "unknown"; } os << ", "; - res = shader.EvaluateResult(obj.local_size.y, &val); + res = eval.EvaluateResult(obj.local_size.y, &val); if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { os << val->data.numeric.scalar.value.uint32_bool_value; } else { os << "unknown"; } os << ", "; - res = shader.EvaluateResult(obj.local_size.z, &val); + res = eval.EvaluateResult(obj.local_size.z, &val); if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { os << val->data.numeric.vector.value[2].value.uint32_bool_value; } @@ -1192,7 +1192,7 @@ void StreamWriteEntryPoint(std::ostream& os, spv_reflect::ShaderModule& shader, } } -void StreamWriteShaderModule(std::ostream& os, spv_reflect::ShaderModule& obj, const char* indent) +void StreamWriteShaderModule(std::ostream& os, const spv_reflect::ShaderModule& obj, const char* indent) { (void)indent; os << "generator : " << ToStringGenerator(obj.GetShaderModule().generator) << "\n"; @@ -1202,7 +1202,7 @@ void StreamWriteShaderModule(std::ostream& os, spv_reflect::ShaderModule& obj, c //os << "shader stage : " << ToStringShaderStage(obj.shader_stage) << "\n"; for (uint32_t i = 0; i < obj.GetShaderModule().entry_point_count; ++i) { - StreamWriteEntryPoint(os, obj, obj.GetShaderModule().entry_points[i], ""); + StreamWriteEntryPoint(os, obj.GetEvaluation(), obj.GetShaderModule().entry_points[i], ""); if (i < (obj.GetShaderModule().entry_point_count - 1)) { os << "\n"; } @@ -1217,7 +1217,7 @@ void StreamWriteShaderModule(std::ostream& os, spv_reflect::ShaderModule& obj, c #define USE_ASSERT(x) ((void)(x)) #endif -void WriteReflection(spv_reflect::ShaderModule& obj, bool flatten_cbuffers, std::ostream& os) +void WriteReflection(const spv_reflect::ShaderModule& obj, bool flatten_cbuffers, std::ostream& os) { const char* t = " "; const char* tt = " "; @@ -1269,7 +1269,7 @@ void WriteReflection(spv_reflect::ShaderModule& obj, bool flatten_cbuffers, std: auto p_var = variables[i]; USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); os << tt << i << ":" << "\n"; - StreamWriteInterfaceVariable(os, obj,*p_var, ttt); + StreamWriteInterfaceVariable(os, obj.GetEvaluation(),*p_var, ttt); if (i < (count - 1)) { os << "\n"; } @@ -1291,7 +1291,7 @@ void WriteReflection(spv_reflect::ShaderModule& obj, bool flatten_cbuffers, std: auto p_var = variables[i]; USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); os << tt << i << ":" << "\n"; - StreamWriteInterfaceVariable(os, obj, *p_var, ttt); + StreamWriteInterfaceVariable(os, obj.GetEvaluation(), *p_var, ttt); if (i < (count - 1)) { os << "\n"; } @@ -1312,7 +1312,7 @@ void WriteReflection(spv_reflect::ShaderModule& obj, bool flatten_cbuffers, std: for (size_t i = 0; i < push_constant_bocks.size(); ++i) { auto p_block = push_constant_bocks[i]; os << tt << i << ":" << "\n"; - StreamWritePushConstantsBlock(os, obj, *p_block, flatten_cbuffers, ttt); + StreamWritePushConstantsBlock(os, obj.GetEvaluation(), *p_block, flatten_cbuffers, ttt); } } @@ -1339,7 +1339,7 @@ void WriteReflection(spv_reflect::ShaderModule& obj, bool flatten_cbuffers, std: auto p_binding = bindings[i]; USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); os << tt << "Binding" << " " << p_binding->set << "." << p_binding->binding << "" << "\n"; - StreamWriteDescriptorBinding(os, obj, *p_binding, true, flatten_cbuffers, ttt); + StreamWriteDescriptorBinding(os, obj.GetEvaluation(), *p_binding, true, flatten_cbuffers, ttt); if (i < (count - 1)) { os << "\n\n"; } diff --git a/common/output_stream.h b/common/output_stream.h index fc4f1784..b69c70a7 100644 --- a/common/output_stream.h +++ b/common/output_stream.h @@ -25,7 +25,7 @@ std::string ToStringComponentType(const SpvReflectTypeDescription& type, uint32_ std::string ToStringType(SpvSourceLanguage src_lang, const SpvReflectTypeDescription& type); //std::ostream& operator<<(std::ostream& os, const spv_reflect::ShaderModule& obj); -void WriteReflection(spv_reflect::ShaderModule& obj, bool flatten_cbuffers, std::ostream& os); +void WriteReflection(const spv_reflect::ShaderModule& obj, bool flatten_cbuffers, std::ostream& os); class SpvReflectToYaml { public: diff --git a/spirv_reflect.c b/spirv_reflect.c index db9561b4..77183647 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -7316,7 +7316,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect } -SpvReflectEvaluation* spvReflectGetEvaluationInterface(SpvReflectShaderModule* p_module) +SpvReflectEvaluation* spvReflectGetEvaluationInterface(const SpvReflectShaderModule* p_module) { // build ast here. return p_module->_internal->evaluator; diff --git a/spirv_reflect.h b/spirv_reflect.h index d7faf1e7..205d6f2a 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -1551,7 +1551,7 @@ const char* spvReflectBlockVariableTypeName( @return If successful, returns the evaluation instance. Otherwise, returns NULL. */ -SpvReflectEvaluation* spvReflectGetEvaluationInterface(SpvReflectShaderModule* p_module); +SpvReflectEvaluation* spvReflectGetEvaluationInterface(const SpvReflectShaderModule* p_module); typedef enum SpvReflectScalarType { SPIRV_REFLECT_SCALAR_TYPE_INVALID, @@ -1643,6 +1643,9 @@ int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id namespace spv_reflect { +// separate evaluation, so that module can be const. +class Evaluation; + /*! \class ShaderModule */ @@ -1660,6 +1663,7 @@ class ShaderModule { SpvReflectResult GetResult() const; const SpvReflectShaderModule& GetShaderModule() const; + Evaluation GetEvaluation() const; uint32_t GetCodeSize() const; const uint32_t* GetCode() const; @@ -1737,6 +1741,38 @@ class ShaderModule { SpvReflectResult ChangeDescriptorSetNumber(const SpvReflectDescriptorSet* p_set, uint32_t new_set_number = SPV_REFLECT_SET_NUMBER_DONT_CHANGE); SpvReflectResult ChangeInputVariableLocation(const SpvReflectInterfaceVariable* p_input_variable, uint32_t new_location); SpvReflectResult ChangeOutputVariableLocation(const SpvReflectInterfaceVariable* p_output_variable, uint32_t new_location); + +private: + // Make noncopyable + ShaderModule(const ShaderModule&); + ShaderModule& operator=(const ShaderModule&); + +private: + mutable SpvReflectResult m_result = SPV_REFLECT_RESULT_NOT_READY; + SpvReflectShaderModule m_module = {}; +}; + +class Evaluation { +public: + Evaluation(SpvReflectEvaluation* eval) :p_eval(eval){} + SpvReflectResult SetSpecConstantValue(uint32_t specId, SpvReflectScalarType type, const SpvReflectScalarValueData* value) + { + if (p_eval) { + return spvReflectSetSpecConstantValue(p_eval, specId, type, value); + } + else { + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + } + } + SpvReflectResult GetSpecConstantValue(uint32_t specId, const SpvReflectValue** value) + { + if (p_eval) { + return spvReflectGetSpecConstantValue(p_eval, specId, value); + } + else { + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + } + } SpvReflectResult EvaluateResult(uint32_t result_id, const SpvReflectValue** result) { if (p_eval) { @@ -1746,16 +1782,17 @@ class ShaderModule { return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; } } - -private: - // Make noncopyable - ShaderModule(const ShaderModule&); - ShaderModule& operator=(const ShaderModule&); - + bool IsRelatedToSpecId(uint32_t result_id, uint32_t specId) + { + if (p_eval) { + return spvReflectIsRelatedToSpecId(p_eval, result_id, specId); + } + else { + return false; + } + } private: - mutable SpvReflectResult m_result = SPV_REFLECT_RESULT_NOT_READY; - SpvReflectShaderModule m_module = {}; - SpvReflectEvaluation* p_eval = nullptr; + SpvReflectEvaluation* p_eval; }; @@ -1781,7 +1818,6 @@ inline ShaderModule::ShaderModule(size_t size, const void* p_code, SpvReflectMod size, p_code, &m_module); - p_eval = spvReflectGetEvaluationInterface(&m_module); } /*! @fn ShaderModule @@ -1795,7 +1831,6 @@ inline ShaderModule::ShaderModule(const std::vector& code, SpvReflectMo code.size(), code.data(), &m_module); - p_eval = spvReflectGetEvaluationInterface(&m_module); } /*! @fn ShaderModule @@ -1809,7 +1844,6 @@ inline ShaderModule::ShaderModule(const std::vector& code, SpvReflectM code.size() * sizeof(uint32_t), code.data(), &m_module); - p_eval = spvReflectGetEvaluationInterface(&m_module); } /*! @fn ~ShaderModule @@ -1853,6 +1887,11 @@ inline const SpvReflectShaderModule& ShaderModule::GetShaderModule() const { return m_module; } +inline Evaluation ShaderModule::GetEvaluation() const +{ + return Evaluation(spvReflectGetEvaluationInterface(&m_module)); +} + /*! @fn GetCodeSize From bfe3643f3587bc2364ce07e6190f4933fa329188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sun, 7 Aug 2022 14:53:33 +0800 Subject: [PATCH 25/44] Add test shaders Adding tests... --- tests/spec_constant/rebuild.sh | 18 + tests/spec_constant/test_32bit.spv | Bin 0 -> 11500 bytes tests/spec_constant/test_32bit.spv.dis | 659 +++++++++++++++++ tests/spec_constant/test_32bit.spv.dis.patch | 10 + tests/spec_constant/test_64bit.spv | Bin 0 -> 11616 bytes tests/spec_constant/test_64bit.spv.dis | 662 ++++++++++++++++++ tests/spec_constant/test_64bit.spv.dis.patch | 27 + tests/spec_constant/test_convert.glsl | 33 + tests/spec_constant/test_convert.spv | Bin 0 -> 2064 bytes tests/spec_constant/test_convert.spv.dis | 123 ++++ .../spec_constant/test_convert.spv.dis.patch | 32 + tests/spec_constant/test_localsizeid.spv | Bin 0 -> 11444 bytes tests/spec_constant/test_localsizeid.spv.dis | 655 +++++++++++++++++ .../test_localsizeid.spv.dis.patch | 13 + tests/spec_constant/test_orig.glsl | 123 ++++ tests/spec_constant/test_orig.spv.dis | 657 +++++++++++++++++ tests/test-spirv-reflect.cpp | 26 + 17 files changed, 3038 insertions(+) create mode 100644 tests/spec_constant/rebuild.sh create mode 100644 tests/spec_constant/test_32bit.spv create mode 100644 tests/spec_constant/test_32bit.spv.dis create mode 100644 tests/spec_constant/test_32bit.spv.dis.patch create mode 100644 tests/spec_constant/test_64bit.spv create mode 100644 tests/spec_constant/test_64bit.spv.dis create mode 100644 tests/spec_constant/test_64bit.spv.dis.patch create mode 100644 tests/spec_constant/test_convert.glsl create mode 100644 tests/spec_constant/test_convert.spv create mode 100644 tests/spec_constant/test_convert.spv.dis create mode 100644 tests/spec_constant/test_convert.spv.dis.patch create mode 100644 tests/spec_constant/test_localsizeid.spv create mode 100644 tests/spec_constant/test_localsizeid.spv.dis create mode 100644 tests/spec_constant/test_localsizeid.spv.dis.patch create mode 100644 tests/spec_constant/test_orig.glsl create mode 100644 tests/spec_constant/test_orig.spv.dis diff --git a/tests/spec_constant/rebuild.sh b/tests/spec_constant/rebuild.sh new file mode 100644 index 00000000..f782b5bf --- /dev/null +++ b/tests/spec_constant/rebuild.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# Creates multi_entrypoint.spv from multi_entrypoint.glsl and +# multi_entrypoint.spv.dis.diff +glslc -fshader-stage=comp --target-spv=spv1.5 test_orig.glsl -o test_32bit.spv +spirv-dis test_32bit.spv > test_orig.spv.dis +cp test_orig.spv.dis test_32bit.spv.dis +patch test_32bit.spv.dis test_32bit.spv.dis.patch +spirv-as --target-env spv1.5 test_32bit.spv.dis -o test_32bit.spv +cp test_orig.spv.dis test_64bit.spv.dis +patch test_64bit.spv.dis test_64bit.spv.dis.patch +spirv-as --target-env spv1.5 test_64bit.spv.dis -o test_64bit.spv +cp test_orig.spv.dis test_localsizeid.spv.dis +patch test_localsizeid.spv.dis test_localsizeid.spv.dis.patch +spirv-as --target-env spv1.5 test_localsizeid.spv.dis -o test_localsizeid.spv +glslc -fshader-stage=comp --target-spv=spv1.5 test_convert.glsl -o test_convert.spv +spirv-dis test_convert.spv > test_convert.spv.dis +patch test_convert.spv.dis test_convert.spv.dis.patch +spirv-as --target-env spv1.5 --preserve-numeric-ids test_convert.spv.dis -o test_convert.spv \ No newline at end of file diff --git a/tests/spec_constant/test_32bit.spv b/tests/spec_constant/test_32bit.spv new file mode 100644 index 0000000000000000000000000000000000000000..b1b58fb83f4fd37e1ff0e42fb9149378e18f943b GIT binary patch literal 11500 zcmZ9Q2b^5hb%!TgB!N%^A({{Z(@Za-H!aq(S{UuZjs`?AE1_LLW+hQ1+1QjdrkG&d zVmmG=N{n0VBzBx`CvgaInw{8*yVI*nda+3X@_l#SSsmT``yI~t|L=Y0yYJ4M*(dt@ zUN*lq_yet0YkuoR{_9xQ>TBsNY|Sfqq}^$sao?_~GuE7Umh+2S{iZUvq;-62kh+i9 zzGd4EeP;&<{dvTEVgYdgaUijfIEYw8EGCu^ONnK~!NeiNa^g^81#uX0IB^7VBykk6 zk~o@JMI1w{CXOYRLUb?oGRI!}snpMMV*~7Bq&+z@K0eYOp4@u(-IMq2x_@SRa%S6( z>B*^W_fBu!wQbL|>lUPS+jeZ7**%pP46-8MxB563o$;|@68AsQdYO9T4dbDYr|72n z6Vz$`MD*y;x^=zvgRPS&I-M)WCr5{-rl{x9Q_rzy%M7}=#?NbN_xA1gljVBf%_T*j ztnPHLB%udeFDLi3bTwyKeM)Qt5j-x%BO>+qQ?=zIu-6tFHU{{56-9K4+jiW5Xkp>CDg6 zODrGq!s_f}l?NX`Sn8VPbKYE1SZB}mnV8;A?Vj}<(MMhP@w?LLT~hj-qb_@1KQYXc z<>z~@-iGnH=VXoA=cKb?XFMl*j$o;4mfy+dlG67)bT{=q-+B9X_x06tL|=8?*YA0A zN$Gn5y4_hn_ncgaE`8gbJL5Ugb3|Wt-Phla=91F)BJ@P+dojB7o!Hk`&k=pqb>D;V znoCOGONw4UL_!a?E+t3bE!2LNdXDI;uKO;+qpz3HrN4Ck_+~-S8k4EX)o!LcMdg?i%r+WXM{pB~^OYHXw=DY3T($9ys={HST`jrQnI{K;We#`K> zGt;FXUxQY6q_@ATsC)hHnA@M8Bl@Z9e*UfLa*6vJu^#E|Z#{L>Z*G5jj_9YZ`}udP zdq;17qtu<|{I0ex-_3pJr{{=%>bl=@yiRj|*H|~_=a;DIH@Cm?#lnw%>bjqQPdm-| zZLn_6Z_K*vZ{PXpIijDs?zaN3)104w;5yCuU2EOzH@81MNAy$I{ro%MY0l3Fx;;Ko zo|g%I`?Yu8OIe;5JxBCY*Zq8F@Djf#9qXa7@|X?cY()2ZZrL$K?e|2_5k1xW_Z%qi zAno2IrEixt?XmH4seP|U_xkSGxr^GqdXDI;uKW64)9zhDm;TlbXt!(6P1L35P}yqf zspp8E>iv86m-i$uvEPl%bDY!zt(&MzzwvuZFSR3jsq0?8Z?U}ex|w=Y^V!@&U3zWW z_u1$CE z`3#nxo#`3MvQIrn^i=QPv%kFadWrk=%eHZ%JM1;;+sRiAwL2Ok=;O#<-`8m0P1U|D zI)8kl2OE7tqvtjH4zl$Cu^vLahuX&xo;~$kH$r#U1yh#$aL802TU1ZqNu3$-PMR6< zUYZ$t!H}C7Y8mcJ<~DL>#QSMx#5-zc=moXNFov z+{aGpd>;ES%uvhl%w#-F&WufH zM`q~N4836Z|4uVQEyFXDF-y*jo6wHT(5o4G!B|P18S2bz1~@r z=P=NE7q!>x$3A|TdY16qy#Me|rgnecgKOO1on)_d&i%cd9G?B(jkdqO`%@1zUi3W$ z{U~AId_M0%doQu>z0~qu@0|Q?Wckj?Kb0Jw{P&^d>&sVr=6cchG-{vU;M@0AX!|;6 z-_yzA+4o1#_RzPldS2tj^LYmP#g|@sNsgbxnZy%>&!Thj`TQt#9}(+*jCz)Ey>ss8 zF0%V^&i$N44$uAkINJT_yC3!Z#*61|FWTqVelukI?IrAYHaR@|{RG;6`u0;VXuP<; zbI>oO`#TryeR_Y+#r^yw^(^6h+|PDu`Oe8-Lk>^=`_c0C<*N^v^LpRE^UzNceqT-@ z;`4ll+ULaiy@dC>gDlTEdFPYEllK9%JbiiU0~;^;UVwg%kmvIr=lVhFg+#3T5Vd^Q zJ12i9S-x}fFC>R2|HEkc`tsHG?43dHelJ2lOVs?2;Pnx~|0!zuu6IuU-DLUB$-kH! zp8SuZW$DWg9sH;8KSsYB-{&s0Oy^}@Ne)luub}O(FH^m= z@q+mZv}ay3e-%%r^O?CDEz^0K>&W5B{1jTIzD)J9#tY^!`eQ`R{4}0S=kwX_LCbVr z=2hhIWd0gjroK$|!HpNp5wy>A&HQydna*eCtI;x@m${xCp3L7s%hZ>tKBV!2Ig0i< zKbNp~JVT$Mmg#(Ez6LGxGla~m$>GWTO|(pXnd;?@7tCwW_NnD8KU2Re_mgEh zFSAV!Po}>IGWBJu4{f|)Zb18+Q8S;zlj(eZhF*)7>AcJ_a(FU-8!b~`rg}x=1#=wj zZ%@tqES^l~GxK$5na<0+mK>hU-$BdNm#IFi@q&3B`h&z}gr8k}p1(^i(|ON6&h`On zna<0cAcrUO_s}x+WvUNvykK_FA0lez@8ijIKHukqXqnE-+(-^j<{zMC>dRCg(RluC z@VB5#e3LVM^dwiPu2Ey|`v5D~i5d8?@ z{M!hh*N4gSoRhbS9G<*CLd(;ar#`CjqVJ7ppDB4K6Y-w#1?qW3totIheAhcCf0iuY zIr%q{X9+#|e@vFIFJHZ~@uKg|=+6@M{r(BwEaCiKLf-4i_I6I*E#&azeF-g3U!MBt z#`E*^d|yfU4B9vD^~==p?(3Sb5ZGWVDq6O_Z1t+f^Imaa!hoZZy7Q=iZC@J4bU;dqjG9`)zs zA$q-w{1=41-_gY7D7|+QvF0zS-A`Vlm)HCidazofm)HC?dS10gFR%F<^!#d#US9LJ z=mpgpy}ah{&<9j&^zxd&M;}`8Ik{wMH+m`3`z< zwMH+m`7U}%wMH+m`A789YK>lA^H1ny)f&CL=AY3AS8Me0ntwqbQmxU;YyK6zyjr7| z*Zdp$&}xldUi0th71bKOyyid9hgECz@|yodA6~7|%WM7%eMGfJFR%F?`p9aHUS9Kk z^ikCsy}agm^vY_DUS9Lx=%cGOdU?(Np#440&!Jvk^S@|+Kl2*ByypMVtE)A7dCd!G Rf46cUJ=eUzzuGP&{vV3Y3W)#! literal 0 HcmV?d00001 diff --git a/tests/spec_constant/test_32bit.spv.dis b/tests/spec_constant/test_32bit.spv.dis new file mode 100644 index 00000000..79611c17 --- /dev/null +++ b/tests/spec_constant/test_32bit.spv.dis @@ -0,0 +1,659 @@ +; SPIR-V +; Version: 1.5 +; Generator: Google Shaderc over Glslang; 10 +; Bound: 254 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %IAdd %ISub %IMul %UDiv %SDiv %SRem %SMod %UMod %LShl %RShl %RSha %IEq %INeq %Ult %Ule %Ugt %Uge %Slt %Sle %Sgt %Sge %Lor %Land %Lnot %And %Or %Xor %Not %Leq %Lneq %Sel + ; should ignore this if working with WorkGroupSize builtin + OpExecutionMode %main LocalSize 2 3 4 + OpSource GLSL 450 + OpSourceExtension "GL_GOOGLE_cpp_style_line_directive" + OpSourceExtension "GL_GOOGLE_include_directive" + OpName %main "main" + OpName %SONE "SONE" + OpName %STWO "STWO" + OpName %UONE "UONE" + OpName %UTWO "UTWO" + OpName %IADD "IADD" + OpName %SSBO_IAdd "SSBO_IAdd" + OpMemberName %SSBO_IAdd 0 "val" + OpMemberName %SSBO_IAdd 1 "dummy" + OpName %IAdd "IAdd" + OpName %ISUB "ISUB" + OpName %SSBO_ISub "SSBO_ISub" + OpMemberName %SSBO_ISub 0 "val" + OpMemberName %SSBO_ISub 1 "dummy" + OpName %ISub "ISub" + OpName %IMUL "IMUL" + OpName %SSBO_IMul "SSBO_IMul" + OpMemberName %SSBO_IMul 0 "val" + OpMemberName %SSBO_IMul 1 "dummy" + OpName %IMul "IMul" + OpName %UDIV "UDIV" + OpName %SSBO_UDiv "SSBO_UDiv" + OpMemberName %SSBO_UDiv 0 "val" + OpMemberName %SSBO_UDiv 1 "dummy" + OpName %UDiv "UDiv" + OpName %SNEG_TWO "SNEG_TWO" + OpName %SDIV "SDIV" + OpName %SSBO_SDiv "SSBO_SDiv" + OpMemberName %SSBO_SDiv 0 "val" + OpMemberName %SSBO_SDiv 1 "dummy" + OpName %SDiv "SDiv" + OpName %SSBO_SRem "SSBO_SRem" + OpMemberName %SSBO_SRem 0 "val" + OpMemberName %SSBO_SRem 1 "dummy" + OpName %SRem "SRem" + OpName %SNEG_THREE "SNEG_THREE" + OpName %SMOD "SMOD" + OpName %SSBO_SMod "SSBO_SMod" + OpMemberName %SSBO_SMod 0 "val" + OpMemberName %SSBO_SMod 1 "dummy" + OpName %SMod "SMod" + OpName %UMOD "UMOD" + OpName %SSBO_UMod "SSBO_UMod" + OpMemberName %SSBO_UMod 0 "val" + OpMemberName %SSBO_UMod 1 "dummy" + OpName %UMod "UMod" + OpName %LSHL "LSHL" + OpName %SSBO_LShl "SSBO_LShl" + OpMemberName %SSBO_LShl 0 "val" + OpMemberName %SSBO_LShl 1 "dummy" + OpName %LShl "LShl" + OpName %RSHL "RSHL" + OpName %SSBO_RShl "SSBO_RShl" + OpMemberName %SSBO_RShl 0 "val" + OpMemberName %SSBO_RShl 1 "dummy" + OpName %RShl "RShl" + OpName %RSHA "RSHA" + OpName %SSBO_RSha "SSBO_RSha" + OpMemberName %SSBO_RSha 0 "val" + OpMemberName %SSBO_RSha 1 "dummy" + OpName %RSha "RSha" + OpName %IEQ "IEQ" + OpName %SSBO_IEq "SSBO_IEq" + OpMemberName %SSBO_IEq 0 "val" + OpMemberName %SSBO_IEq 1 "dummy" + OpName %IEq "IEq" + OpName %INEQ "INEQ" + OpName %SSBO_INeq "SSBO_INeq" + OpMemberName %SSBO_INeq 0 "val" + OpMemberName %SSBO_INeq 1 "dummy" + OpName %INeq "INeq" + OpName %ULT "ULT" + OpName %SSBO_Ult "SSBO_Ult" + OpMemberName %SSBO_Ult 0 "val" + OpMemberName %SSBO_Ult 1 "dummy" + OpName %Ult "Ult" + OpName %ULE "ULE" + OpName %SSBO_Ule "SSBO_Ule" + OpMemberName %SSBO_Ule 0 "val" + OpMemberName %SSBO_Ule 1 "dummy" + OpName %Ule "Ule" + OpName %UGT "UGT" + OpName %SSBO_Ugt "SSBO_Ugt" + OpMemberName %SSBO_Ugt 0 "val" + OpMemberName %SSBO_Ugt 1 "dummy" + OpName %Ugt "Ugt" + OpName %UGE "UGE" + OpName %SSBO_Uge "SSBO_Uge" + OpMemberName %SSBO_Uge 0 "val" + OpMemberName %SSBO_Uge 1 "dummy" + OpName %Uge "Uge" + OpName %SLT "SLT" + OpName %SSBO_Slt "SSBO_Slt" + OpMemberName %SSBO_Slt 0 "val" + OpMemberName %SSBO_Slt 1 "dummy" + OpName %Slt "Slt" + OpName %SLE "SLE" + OpName %SSBO_Sle "SSBO_Sle" + OpMemberName %SSBO_Sle 0 "val" + OpMemberName %SSBO_Sle 1 "dummy" + OpName %Sle "Sle" + OpName %SGT "SGT" + OpName %SSBO_Sgt "SSBO_Sgt" + OpMemberName %SSBO_Sgt 0 "val" + OpMemberName %SSBO_Sgt 1 "dummy" + OpName %Sgt "Sgt" + OpName %SGE "SGE" + OpName %SSBO_Sge "SSBO_Sge" + OpMemberName %SSBO_Sge 0 "val" + OpMemberName %SSBO_Sge 1 "dummy" + OpName %Sge "Sge" + OpName %LOR "LOR" + OpName %SSBO_Lor "SSBO_Lor" + OpMemberName %SSBO_Lor 0 "val" + OpMemberName %SSBO_Lor 1 "dummy" + OpName %Lor "Lor" + OpName %LAND "LAND" + OpName %SSBO_Land "SSBO_Land" + OpMemberName %SSBO_Land 0 "val" + OpMemberName %SSBO_Land 1 "dummy" + OpName %Land "Land" + OpName %LNOT "LNOT" + OpName %SSBO_Lnot "SSBO_Lnot" + OpMemberName %SSBO_Lnot 0 "val" + OpMemberName %SSBO_Lnot 1 "dummy" + OpName %Lnot "Lnot" + OpName %AND "AND" + OpName %SSBO_And "SSBO_And" + OpMemberName %SSBO_And 0 "val" + OpMemberName %SSBO_And 1 "dummy" + OpName %And "And" + OpName %OR "OR" + OpName %SSBO_Or "SSBO_Or" + OpMemberName %SSBO_Or 0 "val" + OpMemberName %SSBO_Or 1 "dummy" + OpName %Or "Or" + OpName %XOR "XOR" + OpName %SSBO_Xor "SSBO_Xor" + OpMemberName %SSBO_Xor 0 "val" + OpMemberName %SSBO_Xor 1 "dummy" + OpName %Xor "Xor" + OpName %NOT "NOT" + OpName %SSBO_Not "SSBO_Not" + OpMemberName %SSBO_Not 0 "val" + OpMemberName %SSBO_Not 1 "dummy" + OpName %Not "Not" + OpName %LEQ "LEQ" + OpName %SSBO_Leq "SSBO_Leq" + OpMemberName %SSBO_Leq 0 "val" + OpMemberName %SSBO_Leq 1 "dummy" + OpName %Leq "Leq" + OpName %LNEQ "LNEQ" + OpName %SSBO_Lneq "SSBO_Lneq" + OpMemberName %SSBO_Lneq 0 "val" + OpMemberName %SSBO_Lneq 1 "dummy" + OpName %Lneq "Lneq" + OpName %SEL "SEL" + OpName %SSBO_Sel "SSBO_Sel" + OpMemberName %SSBO_Sel 0 "val" + OpMemberName %SSBO_Sel 1 "dummy" + OpName %Sel "Sel" + OpName %TRUE "TRUE" + OpName %FALSE "FALSE" + OpDecorate %SONE SpecId 2 + OpDecorate %STWO SpecId 3 + OpDecorate %UONE SpecId 5 + OpDecorate %UTWO SpecId 6 + OpDecorate %_arr_float_19 ArrayStride 4 + OpMemberDecorate %SSBO_IAdd 0 Offset 0 + OpMemberDecorate %SSBO_IAdd 1 Offset 4 + OpDecorate %SSBO_IAdd Block + OpDecorate %IAdd DescriptorSet 0 + OpDecorate %IAdd Binding 0 + OpDecorate %_arr_float_ISUB ArrayStride 4 + OpMemberDecorate %SSBO_ISub 0 Offset 0 + OpMemberDecorate %SSBO_ISub 1 Offset 4 + OpDecorate %SSBO_ISub Block + OpDecorate %ISub DescriptorSet 0 + OpDecorate %ISub Binding 1 + OpDecorate %_arr_float_37 ArrayStride 4 + OpMemberDecorate %SSBO_IMul 0 Offset 0 + OpMemberDecorate %SSBO_IMul 1 Offset 4 + OpDecorate %SSBO_IMul Block + OpDecorate %IMul DescriptorSet 0 + OpDecorate %IMul Binding 2 + OpDecorate %_arr_float_UDIV ArrayStride 4 + OpMemberDecorate %SSBO_UDiv 0 Offset 0 + OpMemberDecorate %SSBO_UDiv 1 Offset 4 + OpDecorate %SSBO_UDiv Block + OpDecorate %UDiv DescriptorSet 0 + OpDecorate %UDiv Binding 3 + OpDecorate %SNEG_TWO SpecId 4 + OpDecorate %_arr_float_52 ArrayStride 4 + OpMemberDecorate %SSBO_SDiv 0 Offset 0 + OpMemberDecorate %SSBO_SDiv 1 Offset 4 + OpDecorate %SSBO_SDiv Block + OpDecorate %SDiv DescriptorSet 0 + OpDecorate %SDiv Binding 4 + OpDecorate %_arr_float_uint_1 ArrayStride 4 + OpMemberDecorate %SSBO_SRem 0 Offset 0 + OpMemberDecorate %SSBO_SRem 1 Offset 4 + OpDecorate %SSBO_SRem Block + OpDecorate %SRem DescriptorSet 0 + OpDecorate %SRem Binding 5 + OpDecorate %SNEG_THREE SpecId 7 + OpDecorate %_arr_float_66 ArrayStride 4 + OpMemberDecorate %SSBO_SMod 0 Offset 0 + OpMemberDecorate %SSBO_SMod 1 Offset 4 + OpDecorate %SSBO_SMod Block + OpDecorate %SMod DescriptorSet 0 + OpDecorate %SMod Binding 6 + OpDecorate %_arr_float_73 ArrayStride 4 + OpMemberDecorate %SSBO_UMod 0 Offset 0 + OpMemberDecorate %SSBO_UMod 1 Offset 4 + OpDecorate %SSBO_UMod Block + OpDecorate %UMod DescriptorSet 0 + OpDecorate %UMod Binding 7 + OpDecorate %_arr_float_81 ArrayStride 4 + OpMemberDecorate %SSBO_LShl 0 Offset 0 + OpMemberDecorate %SSBO_LShl 1 Offset 4 + OpDecorate %SSBO_LShl Block + OpDecorate %LShl DescriptorSet 0 + OpDecorate %LShl Binding 8 + OpDecorate %_arr_float_89 ArrayStride 4 + OpMemberDecorate %SSBO_RShl 0 Offset 0 + OpMemberDecorate %SSBO_RShl 1 Offset 4 + OpDecorate %SSBO_RShl Block + OpDecorate %RShl DescriptorSet 0 + OpDecorate %RShl Binding 9 + OpDecorate %_arr_float_100 ArrayStride 4 + OpMemberDecorate %SSBO_RSha 0 Offset 0 + OpMemberDecorate %SSBO_RSha 1 Offset 4 + OpDecorate %SSBO_RSha Block + OpDecorate %RSha DescriptorSet 0 + OpDecorate %RSha Binding 10 + OpDecorate %_arr_float_109 ArrayStride 4 + OpMemberDecorate %SSBO_IEq 0 Offset 0 + OpMemberDecorate %SSBO_IEq 1 Offset 4 + OpDecorate %SSBO_IEq Block + OpDecorate %IEq DescriptorSet 0 + OpDecorate %IEq Binding 11 + OpDecorate %_arr_float_116 ArrayStride 4 + OpMemberDecorate %SSBO_INeq 0 Offset 0 + OpMemberDecorate %SSBO_INeq 1 Offset 4 + OpDecorate %SSBO_INeq Block + OpDecorate %INeq DescriptorSet 0 + OpDecorate %INeq Binding 12 + OpDecorate %_arr_float_123 ArrayStride 4 + OpMemberDecorate %SSBO_Ult 0 Offset 0 + OpMemberDecorate %SSBO_Ult 1 Offset 4 + OpDecorate %SSBO_Ult Block + OpDecorate %Ult DescriptorSet 0 + OpDecorate %Ult Binding 13 + OpDecorate %_arr_float_130 ArrayStride 4 + OpMemberDecorate %SSBO_Ule 0 Offset 0 + OpMemberDecorate %SSBO_Ule 1 Offset 4 + OpDecorate %SSBO_Ule Block + OpDecorate %Ule DescriptorSet 0 + OpDecorate %Ule Binding 14 + OpDecorate %_arr_float_137 ArrayStride 4 + OpMemberDecorate %SSBO_Ugt 0 Offset 0 + OpMemberDecorate %SSBO_Ugt 1 Offset 4 + OpDecorate %SSBO_Ugt Block + OpDecorate %Ugt DescriptorSet 0 + OpDecorate %Ugt Binding 15 + OpDecorate %_arr_float_144 ArrayStride 4 + OpMemberDecorate %SSBO_Uge 0 Offset 0 + OpMemberDecorate %SSBO_Uge 1 Offset 4 + OpDecorate %SSBO_Uge Block + OpDecorate %Uge DescriptorSet 0 + OpDecorate %Uge Binding 16 + OpDecorate %_arr_float_151 ArrayStride 4 + OpMemberDecorate %SSBO_Slt 0 Offset 0 + OpMemberDecorate %SSBO_Slt 1 Offset 4 + OpDecorate %SSBO_Slt Block + OpDecorate %Slt DescriptorSet 0 + OpDecorate %Slt Binding 17 + OpDecorate %_arr_float_158 ArrayStride 4 + OpMemberDecorate %SSBO_Sle 0 Offset 0 + OpMemberDecorate %SSBO_Sle 1 Offset 4 + OpDecorate %SSBO_Sle Block + OpDecorate %Sle DescriptorSet 0 + OpDecorate %Sle Binding 18 + OpDecorate %_arr_float_165 ArrayStride 4 + OpMemberDecorate %SSBO_Sgt 0 Offset 0 + OpMemberDecorate %SSBO_Sgt 1 Offset 4 + OpDecorate %SSBO_Sgt Block + OpDecorate %Sgt DescriptorSet 0 + OpDecorate %Sgt Binding 19 + OpDecorate %_arr_float_172 ArrayStride 4 + OpMemberDecorate %SSBO_Sge 0 Offset 0 + OpMemberDecorate %SSBO_Sge 1 Offset 4 + OpDecorate %SSBO_Sge Block + OpDecorate %Sge DescriptorSet 0 + OpDecorate %Sge Binding 20 + OpDecorate %_arr_float_179 ArrayStride 4 + OpMemberDecorate %SSBO_Lor 0 Offset 0 + OpMemberDecorate %SSBO_Lor 1 Offset 4 + OpDecorate %SSBO_Lor Block + OpDecorate %Lor DescriptorSet 0 + OpDecorate %Lor Binding 21 + OpDecorate %_arr_float_186 ArrayStride 4 + OpMemberDecorate %SSBO_Land 0 Offset 0 + OpMemberDecorate %SSBO_Land 1 Offset 4 + OpDecorate %SSBO_Land Block + OpDecorate %Land DescriptorSet 0 + OpDecorate %Land Binding 22 + OpDecorate %_arr_float_193 ArrayStride 4 + OpMemberDecorate %SSBO_Lnot 0 Offset 0 + OpMemberDecorate %SSBO_Lnot 1 Offset 4 + OpDecorate %SSBO_Lnot Block + OpDecorate %Lnot DescriptorSet 0 + OpDecorate %Lnot Binding 23 + OpDecorate %_arr_float_200 ArrayStride 4 + OpMemberDecorate %SSBO_And 0 Offset 0 + OpMemberDecorate %SSBO_And 1 Offset 4 + OpDecorate %SSBO_And Block + OpDecorate %And DescriptorSet 0 + OpDecorate %And Binding 24 + OpDecorate %_arr_float_208 ArrayStride 4 + OpMemberDecorate %SSBO_Or 0 Offset 0 + OpMemberDecorate %SSBO_Or 1 Offset 4 + OpDecorate %SSBO_Or Block + OpDecorate %Or DescriptorSet 0 + OpDecorate %Or Binding 24 + OpDecorate %_arr_float_215 ArrayStride 4 + OpMemberDecorate %SSBO_Xor 0 Offset 0 + OpMemberDecorate %SSBO_Xor 1 Offset 4 + OpDecorate %SSBO_Xor Block + OpDecorate %Xor DescriptorSet 0 + OpDecorate %Xor Binding 24 + OpDecorate %_arr_float_223 ArrayStride 4 + OpMemberDecorate %SSBO_Not 0 Offset 0 + OpMemberDecorate %SSBO_Not 1 Offset 4 + OpDecorate %SSBO_Not Block + OpDecorate %Not DescriptorSet 0 + OpDecorate %Not Binding 25 + OpDecorate %_arr_float_230 ArrayStride 4 + OpMemberDecorate %SSBO_Leq 0 Offset 0 + OpMemberDecorate %SSBO_Leq 1 Offset 4 + OpDecorate %SSBO_Leq Block + OpDecorate %Leq DescriptorSet 0 + OpDecorate %Leq Binding 26 + OpDecorate %_arr_float_237 ArrayStride 4 + OpMemberDecorate %SSBO_Lneq 0 Offset 0 + OpMemberDecorate %SSBO_Lneq 1 Offset 4 + OpDecorate %SSBO_Lneq Block + OpDecorate %Lneq DescriptorSet 0 + OpDecorate %Lneq Binding 27 + OpDecorate %_arr_float_SEL ArrayStride 4 + OpMemberDecorate %SSBO_Sel 0 Offset 0 + OpMemberDecorate %SSBO_Sel 1 Offset 4 + OpDecorate %SSBO_Sel Block + OpDecorate %Sel DescriptorSet 0 + OpDecorate %Sel Binding 28 + OpDecorate %249 SpecId 8 + OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize + OpDecorate %TRUE SpecId 0 + OpDecorate %FALSE SpecId 1 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %int = OpTypeInt 32 1 + %SONE = OpSpecConstant %int 1 + %STWO = OpSpecConstant %int 2 + %10 = OpSpecConstantOp %int IAdd %SONE %STWO + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %13 = OpSpecConstantOp %uint IAdd %10 %uint_0 + %UONE = OpSpecConstant %uint 1 + %15 = OpSpecConstantOp %uint IAdd %13 %UONE + %UTWO = OpSpecConstant %uint 2 + %IADD = OpSpecConstantOp %uint IAdd %15 %UTWO + %uint_5 = OpConstant %uint 5 + %19 = OpSpecConstantOp %uint ISub %IADD %uint_5 +%_arr_float_19 = OpTypeArray %float %19 + %SSBO_IAdd = OpTypeStruct %_arr_float_19 %float +%_ptr_StorageBuffer_SSBO_IAdd = OpTypePointer StorageBuffer %SSBO_IAdd + %IAdd = OpVariable %_ptr_StorageBuffer_SSBO_IAdd StorageBuffer + %int_0 = OpConstant %int 0 + %float_0 = OpConstant %float 0 +%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float + %28 = OpSpecConstantOp %uint IAdd %SONE %uint_0 + %ISUB = OpSpecConstantOp %uint ISub %UTWO %28 +%_arr_float_ISUB = OpTypeArray %float %ISUB + %SSBO_ISub = OpTypeStruct %_arr_float_ISUB %float +%_ptr_StorageBuffer_SSBO_ISub = OpTypePointer StorageBuffer %SSBO_ISub + %ISub = OpVariable %_ptr_StorageBuffer_SSBO_ISub StorageBuffer + %IMUL = OpSpecConstantOp %uint IMul %UTWO %UTWO + %uint_3 = OpConstant %uint 3 + %37 = OpSpecConstantOp %uint ISub %IMUL %uint_3 +%_arr_float_37 = OpTypeArray %float %37 + %SSBO_IMul = OpTypeStruct %_arr_float_37 %float +%_ptr_StorageBuffer_SSBO_IMul = OpTypePointer StorageBuffer %SSBO_IMul + %IMul = OpVariable %_ptr_StorageBuffer_SSBO_IMul StorageBuffer + %UDIV = OpSpecConstantOp %uint UDiv %UTWO %UTWO +%_arr_float_UDIV = OpTypeArray %float %UDIV + %SSBO_UDiv = OpTypeStruct %_arr_float_UDIV %float +%_ptr_StorageBuffer_SSBO_UDiv = OpTypePointer StorageBuffer %SSBO_UDiv + %UDiv = OpVariable %_ptr_StorageBuffer_SSBO_UDiv StorageBuffer + %SNEG_TWO = OpSpecConstant %int -2 + %SDIV = OpSpecConstantOp %int SDiv %STWO %SNEG_TWO + %int_2 = OpConstant %int 2 + %52 = OpSpecConstantOp %int IAdd %SDIV %int_2 +%_arr_float_52 = OpTypeArray %float %52 + %SSBO_SDiv = OpTypeStruct %_arr_float_52 %float +%_ptr_StorageBuffer_SSBO_SDiv = OpTypePointer StorageBuffer %SSBO_SDiv + %SDiv = OpVariable %_ptr_StorageBuffer_SSBO_SDiv StorageBuffer + %uint_1 = OpConstant %uint 1 +%_arr_float_uint_1 = OpTypeArray %float %uint_1 + %SSBO_SRem = OpTypeStruct %_arr_float_uint_1 %float +%_ptr_StorageBuffer_SSBO_SRem = OpTypePointer StorageBuffer %SSBO_SRem + %SRem = OpVariable %_ptr_StorageBuffer_SSBO_SRem StorageBuffer + %SNEG_THREE = OpSpecConstant %int -3 + %SMOD = OpSpecConstantOp %int SMod %STWO %SNEG_THREE + %66 = OpSpecConstantOp %int IAdd %SMOD %int_2 +%_arr_float_66 = OpTypeArray %float %66 + %SSBO_SMod = OpTypeStruct %_arr_float_66 %float +%_ptr_StorageBuffer_SSBO_SMod = OpTypePointer StorageBuffer %SSBO_SMod + %SMod = OpVariable %_ptr_StorageBuffer_SSBO_SMod StorageBuffer + %UMOD = OpSpecConstantOp %uint UMod %IADD %IMUL + %73 = OpSpecConstantOp %uint ISub %UMOD %uint_1 +%_arr_float_73 = OpTypeArray %float %73 + %SSBO_UMod = OpTypeStruct %_arr_float_73 %float +%_ptr_StorageBuffer_SSBO_UMod = OpTypePointer StorageBuffer %SSBO_UMod + %UMod = OpVariable %_ptr_StorageBuffer_SSBO_UMod StorageBuffer + %LSHL = OpSpecConstantOp %uint ShiftLeftLogical %IADD %ISUB + %uint_11 = OpConstant %uint 11 + %81 = OpSpecConstantOp %uint ISub %LSHL %uint_11 +%_arr_float_81 = OpTypeArray %float %81 + %SSBO_LShl = OpTypeStruct %_arr_float_81 %float +%_ptr_StorageBuffer_SSBO_LShl = OpTypePointer StorageBuffer %SSBO_LShl + %LShl = OpVariable %_ptr_StorageBuffer_SSBO_LShl StorageBuffer + %RSHL = OpSpecConstantOp %uint ShiftRightLogical %IADD %ISUB + %uint_2 = OpConstant %uint 2 + %89 = OpSpecConstantOp %uint ISub %RSHL %uint_2 +%_arr_float_89 = OpTypeArray %float %89 + %SSBO_RShl = OpTypeStruct %_arr_float_89 %float +%_ptr_StorageBuffer_SSBO_RShl = OpTypePointer StorageBuffer %SSBO_RShl + %RShl = OpVariable %_ptr_StorageBuffer_SSBO_RShl StorageBuffer + %95 = OpSpecConstantOp %int IAdd %IADD %uint_0 + %96 = OpSpecConstantOp %int SNegate %95 + %97 = OpSpecConstantOp %int SNegate %SDIV + %RSHA = OpSpecConstantOp %int ShiftRightArithmetic %96 %97 + %int_4 = OpConstant %int 4 + %100 = OpSpecConstantOp %int IAdd %RSHA %int_4 +%_arr_float_100 = OpTypeArray %float %100 + %SSBO_RSha = OpTypeStruct %_arr_float_100 %float +%_ptr_StorageBuffer_SSBO_RSha = OpTypePointer StorageBuffer %SSBO_RSha + %RSha = OpVariable %_ptr_StorageBuffer_SSBO_RSha StorageBuffer + %bool = OpTypeBool + %IEQ = OpSpecConstantOp %bool IEqual %IADD %ISUB + %int_1 = OpConstant %int 1 + %109 = OpSpecConstantOp %int Select %IEQ %int_2 %int_1 +%_arr_float_109 = OpTypeArray %float %109 + %SSBO_IEq = OpTypeStruct %_arr_float_109 %float +%_ptr_StorageBuffer_SSBO_IEq = OpTypePointer StorageBuffer %SSBO_IEq + %IEq = OpVariable %_ptr_StorageBuffer_SSBO_IEq StorageBuffer + %INEQ = OpSpecConstantOp %bool INotEqual %IADD %ISUB + %116 = OpSpecConstantOp %int Select %INEQ %int_1 %int_2 +%_arr_float_116 = OpTypeArray %float %116 + %SSBO_INeq = OpTypeStruct %_arr_float_116 %float +%_ptr_StorageBuffer_SSBO_INeq = OpTypePointer StorageBuffer %SSBO_INeq + %INeq = OpVariable %_ptr_StorageBuffer_SSBO_INeq StorageBuffer + %ULT = OpSpecConstantOp %bool ULessThan %IADD %ISUB + %123 = OpSpecConstantOp %int Select %ULT %int_2 %int_1 +%_arr_float_123 = OpTypeArray %float %123 + %SSBO_Ult = OpTypeStruct %_arr_float_123 %float +%_ptr_StorageBuffer_SSBO_Ult = OpTypePointer StorageBuffer %SSBO_Ult + %Ult = OpVariable %_ptr_StorageBuffer_SSBO_Ult StorageBuffer + %ULE = OpSpecConstantOp %bool ULessThanEqual %IADD %ISUB + %130 = OpSpecConstantOp %int Select %ULE %int_2 %int_1 +%_arr_float_130 = OpTypeArray %float %130 + %SSBO_Ule = OpTypeStruct %_arr_float_130 %float +%_ptr_StorageBuffer_SSBO_Ule = OpTypePointer StorageBuffer %SSBO_Ule + %Ule = OpVariable %_ptr_StorageBuffer_SSBO_Ule StorageBuffer + %UGT = OpSpecConstantOp %bool UGreaterThan %IADD %ISUB + %137 = OpSpecConstantOp %int Select %UGT %int_1 %int_2 +%_arr_float_137 = OpTypeArray %float %137 + %SSBO_Ugt = OpTypeStruct %_arr_float_137 %float +%_ptr_StorageBuffer_SSBO_Ugt = OpTypePointer StorageBuffer %SSBO_Ugt + %Ugt = OpVariable %_ptr_StorageBuffer_SSBO_Ugt StorageBuffer + %UGE = OpSpecConstantOp %bool UGreaterThanEqual %IADD %ISUB + %144 = OpSpecConstantOp %int Select %UGE %int_1 %int_2 +%_arr_float_144 = OpTypeArray %float %144 + %SSBO_Uge = OpTypeStruct %_arr_float_144 %float +%_ptr_StorageBuffer_SSBO_Uge = OpTypePointer StorageBuffer %SSBO_Uge + %Uge = OpVariable %_ptr_StorageBuffer_SSBO_Uge StorageBuffer + %SLT = OpSpecConstantOp %bool SLessThan %SMOD %int_1 + %151 = OpSpecConstantOp %int Select %SLT %int_1 %int_2 +%_arr_float_151 = OpTypeArray %float %151 + %SSBO_Slt = OpTypeStruct %_arr_float_151 %float +%_ptr_StorageBuffer_SSBO_Slt = OpTypePointer StorageBuffer %SSBO_Slt + %Slt = OpVariable %_ptr_StorageBuffer_SSBO_Slt StorageBuffer + %SLE = OpSpecConstantOp %bool SLessThanEqual %SMOD %int_1 + %158 = OpSpecConstantOp %int Select %SLE %int_1 %int_2 +%_arr_float_158 = OpTypeArray %float %158 + %SSBO_Sle = OpTypeStruct %_arr_float_158 %float +%_ptr_StorageBuffer_SSBO_Sle = OpTypePointer StorageBuffer %SSBO_Sle + %Sle = OpVariable %_ptr_StorageBuffer_SSBO_Sle StorageBuffer + %SGT = OpSpecConstantOp %bool SGreaterThan %SMOD %int_1 + %165 = OpSpecConstantOp %int Select %SGT %int_2 %int_1 +%_arr_float_165 = OpTypeArray %float %165 + %SSBO_Sgt = OpTypeStruct %_arr_float_165 %float +%_ptr_StorageBuffer_SSBO_Sgt = OpTypePointer StorageBuffer %SSBO_Sgt + %Sgt = OpVariable %_ptr_StorageBuffer_SSBO_Sgt StorageBuffer + %SGE = OpSpecConstantOp %bool SGreaterThanEqual %SMOD %int_1 + %172 = OpSpecConstantOp %int Select %SGE %int_2 %int_1 +%_arr_float_172 = OpTypeArray %float %172 + %SSBO_Sge = OpTypeStruct %_arr_float_172 %float +%_ptr_StorageBuffer_SSBO_Sge = OpTypePointer StorageBuffer %SSBO_Sge + %Sge = OpVariable %_ptr_StorageBuffer_SSBO_Sge StorageBuffer + %LOR = OpSpecConstantOp %bool LogicalOr %IEQ %SLT + %179 = OpSpecConstantOp %int Select %LOR %int_1 %int_2 +%_arr_float_179 = OpTypeArray %float %179 + %SSBO_Lor = OpTypeStruct %_arr_float_179 %float +%_ptr_StorageBuffer_SSBO_Lor = OpTypePointer StorageBuffer %SSBO_Lor + %Lor = OpVariable %_ptr_StorageBuffer_SSBO_Lor StorageBuffer + %LAND = OpSpecConstantOp %bool LogicalAnd %IEQ %SLT + %186 = OpSpecConstantOp %int Select %LAND %int_2 %int_1 +%_arr_float_186 = OpTypeArray %float %186 + %SSBO_Land = OpTypeStruct %_arr_float_186 %float +%_ptr_StorageBuffer_SSBO_Land = OpTypePointer StorageBuffer %SSBO_Land + %Land = OpVariable %_ptr_StorageBuffer_SSBO_Land StorageBuffer + %LNOT = OpSpecConstantOp %bool LogicalNot %LOR + %193 = OpSpecConstantOp %int Select %LNOT %int_2 %int_1 +%_arr_float_193 = OpTypeArray %float %193 + %SSBO_Lnot = OpTypeStruct %_arr_float_193 %float +%_ptr_StorageBuffer_SSBO_Lnot = OpTypePointer StorageBuffer %SSBO_Lnot + %Lnot = OpVariable %_ptr_StorageBuffer_SSBO_Lnot StorageBuffer + %AND = OpSpecConstantOp %uint BitwiseAnd %IADD %IADD + %200 = OpSpecConstantOp %uint ISub %AND %uint_5 +%_arr_float_200 = OpTypeArray %float %200 + %SSBO_And = OpTypeStruct %_arr_float_200 %float +%_ptr_StorageBuffer_SSBO_And = OpTypePointer StorageBuffer %SSBO_And + %And = OpVariable %_ptr_StorageBuffer_SSBO_And StorageBuffer + %OR = OpSpecConstantOp %uint BitwiseOr %IADD %ISUB + %uint_6 = OpConstant %uint 6 + %208 = OpSpecConstantOp %uint ISub %OR %uint_6 +%_arr_float_208 = OpTypeArray %float %208 + %SSBO_Or = OpTypeStruct %_arr_float_208 %float +%_ptr_StorageBuffer_SSBO_Or = OpTypePointer StorageBuffer %SSBO_Or + %Or = OpVariable %_ptr_StorageBuffer_SSBO_Or StorageBuffer + %XOR = OpSpecConstantOp %uint BitwiseXor %IADD %IADD + %215 = OpSpecConstantOp %uint IAdd %XOR %uint_1 +%_arr_float_215 = OpTypeArray %float %215 + %SSBO_Xor = OpTypeStruct %_arr_float_215 %float +%_ptr_StorageBuffer_SSBO_Xor = OpTypePointer StorageBuffer %SSBO_Xor + %Xor = OpVariable %_ptr_StorageBuffer_SSBO_Xor StorageBuffer + %NOT = OpSpecConstantOp %uint Not %XOR +%uint_4294967294 = OpConstant %uint 4294967294 + %223 = OpSpecConstantOp %uint ISub %NOT %uint_4294967294 +%_arr_float_223 = OpTypeArray %float %223 + %SSBO_Not = OpTypeStruct %_arr_float_223 %float +%_ptr_StorageBuffer_SSBO_Not = OpTypePointer StorageBuffer %SSBO_Not + %Not = OpVariable %_ptr_StorageBuffer_SSBO_Not StorageBuffer + %LEQ = OpSpecConstantOp %bool LogicalEqual %LAND %LNOT + %230 = OpSpecConstantOp %int Select %LEQ %int_1 %int_2 +%_arr_float_230 = OpTypeArray %float %230 + %SSBO_Leq = OpTypeStruct %_arr_float_230 %float +%_ptr_StorageBuffer_SSBO_Leq = OpTypePointer StorageBuffer %SSBO_Leq + %Leq = OpVariable %_ptr_StorageBuffer_SSBO_Leq StorageBuffer + %LNEQ = OpSpecConstantOp %bool LogicalNotEqual %LAND %LNOT + %237 = OpSpecConstantOp %int Select %LNEQ %int_2 %int_1 +%_arr_float_237 = OpTypeArray %float %237 + %SSBO_Lneq = OpTypeStruct %_arr_float_237 %float +%_ptr_StorageBuffer_SSBO_Lneq = OpTypePointer StorageBuffer %SSBO_Lneq + %Lneq = OpVariable %_ptr_StorageBuffer_SSBO_Lneq StorageBuffer + %SEL = OpSpecConstantOp %uint Select %IEQ %IADD %ISUB +%_arr_float_SEL = OpTypeArray %float %SEL + %SSBO_Sel = OpTypeStruct %_arr_float_SEL %float +%_ptr_StorageBuffer_SSBO_Sel = OpTypePointer StorageBuffer %SSBO_Sel + %Sel = OpVariable %_ptr_StorageBuffer_SSBO_Sel StorageBuffer + ; default value should be respected, even if no compiler write things other than 1 + %249 = OpSpecConstant %uint 4 + %v3uint = OpTypeVector %uint 3 +%gl_WorkGroupSize = OpSpecConstantComposite %v3uint %249 %uint_1 %uint_1 + %TRUE = OpSpecConstantTrue %bool + %FALSE = OpSpecConstantFalse %bool + %main = OpFunction %void None %3 + %5 = OpLabel + %27 = OpAccessChain %_ptr_StorageBuffer_float %IAdd %int_0 %int_0 + OpStore %27 %float_0 + %34 = OpAccessChain %_ptr_StorageBuffer_float %ISub %int_0 %int_0 + OpStore %34 %float_0 + %42 = OpAccessChain %_ptr_StorageBuffer_float %IMul %int_0 %int_0 + OpStore %42 %float_0 + %48 = OpAccessChain %_ptr_StorageBuffer_float %UDiv %int_0 %int_0 + OpStore %48 %float_0 + %57 = OpAccessChain %_ptr_StorageBuffer_float %SDiv %int_0 %int_0 + OpStore %57 %float_0 + %63 = OpAccessChain %_ptr_StorageBuffer_float %SRem %int_0 %int_0 + OpStore %63 %float_0 + %71 = OpAccessChain %_ptr_StorageBuffer_float %SMod %int_0 %int_0 + OpStore %71 %float_0 + %78 = OpAccessChain %_ptr_StorageBuffer_float %UMod %int_0 %int_0 + OpStore %78 %float_0 + %86 = OpAccessChain %_ptr_StorageBuffer_float %LShl %int_0 %int_0 + OpStore %86 %float_0 + %94 = OpAccessChain %_ptr_StorageBuffer_float %RShl %int_0 %int_0 + OpStore %94 %float_0 + %105 = OpAccessChain %_ptr_StorageBuffer_float %RSha %int_0 %int_0 + OpStore %105 %float_0 + %114 = OpAccessChain %_ptr_StorageBuffer_float %IEq %int_0 %int_0 + OpStore %114 %float_0 + %121 = OpAccessChain %_ptr_StorageBuffer_float %INeq %int_0 %int_0 + OpStore %121 %float_0 + %128 = OpAccessChain %_ptr_StorageBuffer_float %Ult %int_0 %int_0 + OpStore %128 %float_0 + %135 = OpAccessChain %_ptr_StorageBuffer_float %Ule %int_0 %int_0 + OpStore %135 %float_0 + %142 = OpAccessChain %_ptr_StorageBuffer_float %Ugt %int_0 %int_0 + OpStore %142 %float_0 + %149 = OpAccessChain %_ptr_StorageBuffer_float %Uge %int_0 %int_0 + OpStore %149 %float_0 + %156 = OpAccessChain %_ptr_StorageBuffer_float %Slt %int_0 %int_0 + OpStore %156 %float_0 + %163 = OpAccessChain %_ptr_StorageBuffer_float %Sle %int_0 %int_0 + OpStore %163 %float_0 + %170 = OpAccessChain %_ptr_StorageBuffer_float %Sgt %int_0 %int_0 + OpStore %170 %float_0 + %177 = OpAccessChain %_ptr_StorageBuffer_float %Sge %int_0 %int_0 + OpStore %177 %float_0 + %184 = OpAccessChain %_ptr_StorageBuffer_float %Lor %int_0 %int_0 + OpStore %184 %float_0 + %191 = OpAccessChain %_ptr_StorageBuffer_float %Land %int_0 %int_0 + OpStore %191 %float_0 + %198 = OpAccessChain %_ptr_StorageBuffer_float %Lnot %int_0 %int_0 + OpStore %198 %float_0 + %205 = OpAccessChain %_ptr_StorageBuffer_float %And %int_0 %int_0 + OpStore %205 %float_0 + %213 = OpAccessChain %_ptr_StorageBuffer_float %Or %int_0 %int_0 + OpStore %213 %float_0 + %220 = OpAccessChain %_ptr_StorageBuffer_float %Xor %int_0 %int_0 + OpStore %220 %float_0 + %228 = OpAccessChain %_ptr_StorageBuffer_float %Not %int_0 %int_0 + OpStore %228 %float_0 + %235 = OpAccessChain %_ptr_StorageBuffer_float %Leq %int_0 %int_0 + OpStore %235 %float_0 + %242 = OpAccessChain %_ptr_StorageBuffer_float %Lneq %int_0 %int_0 + OpStore %242 %float_0 + %248 = OpAccessChain %_ptr_StorageBuffer_float %Sel %int_0 %int_0 + OpStore %248 %float_0 + OpReturn + OpFunctionEnd diff --git a/tests/spec_constant/test_32bit.spv.dis.patch b/tests/spec_constant/test_32bit.spv.dis.patch new file mode 100644 index 00000000..c1283b9f --- /dev/null +++ b/tests/spec_constant/test_32bit.spv.dis.patch @@ -0,0 +1,10 @@ +10c10,11 +< OpExecutionMode %main LocalSize 1 1 1 +--- +> ; should ignore this if working with WorkGroupSize builtin +> OpExecutionMode %main LocalSize 2 3 4 +587c588,589 +< %249 = OpSpecConstant %uint 1 +--- +> ; default value should be respected, even if no compiler write things other than 1 +> %249 = OpSpecConstant %uint 4 diff --git a/tests/spec_constant/test_64bit.spv b/tests/spec_constant/test_64bit.spv new file mode 100644 index 0000000000000000000000000000000000000000..672de13b20ebe09f082b97b872b032b0d1185d3c GIT binary patch literal 11616 zcmZ9Q2b`T%nTM}al0Zm<5L$=<0TGlE0wOho876}_GdMRFA|jKJ86Y}IC`l9xj))@m z-h1!8_hs$9yKC9iUCS2Bu617-A_z_hK(|?4_SdeJA%iz%EAGlOyBfBkkeIZP#BvdDHHjXQn4-w(p#toZ5cl z^tRpG_fETRL0Y$c=eC(WQ+dH4EAoA-kA=}09~&ld{{yXis5f0c9{M z^kC~=bkF=>uB$i()T3w#%`Nb`kqYg_1(B1^B;&xxKRSn8VPce1&p^gR>ZO?}UD-oD*^ef1pCS6%n@d){19`ra4a z?rfNQPR>S`zU|I+@to*6qOZE{>u*PMN$Gn(^hD}=4!ZQ6*w^a3S-fV>D#A&voQp&#`Hn+EdRFJ=an1-*ce+29NeGp-X>jh&A2zrqa_N zjncC_vzxN?)N@2n_5MBk%Wt}u*zf+#ciY3IpAT)*Z<@07D-SYt^i$XUmf>}0rb|D* z2CeQ$Z+{n4_xfEsw?92c^i$XU{9DuI68AS^J<{9X2I{8Y-2U_&(NA6X^Y2#o+TQ*~ zsXNX2U1D9noBPgB&k_C9b-(3!o#y-=VBMUbU!tbp-2TcJ3qSg)>wf+{?KJ1N(YiUm zG3&Cwednj=h<@t2-wM1=bAJAT>on(gsdca4-2U_&(NA6X^Y478IX@rh_V`43UMBSI z*WPs_WqDro9MMl*_w${>OZ=X6tcS+RV>XDh3Ek_tb>|ed-xEDY^i=QPbD+F~w0oD7 zzFpR|$HvR0_Pq?<>$`K;Zfg7LIijz+?(2I^yLSm)`dgQy-L5@1Q({n^Wb=_|jo|o8flDgge#%`f5{o3W{u=LY& zM87T6bwA%Jy~Oj{YMp*#uSWNJ?wtFL)pJBo_5M8vTC4Hey-UhIx1l@3ZR)|6&tU1< znVz96`_ywpPxbyi`^!78m$*;AY?~&!!(OAlhJ5i*yQ49JK9=nDeU0|rRPDQ>^T#!M zu+hgidS0WiC0h>=8z97csC^va*;CJTBXoCNFlD(9hfMV`MfLP`)R__Qq?r-#rJ11@ z47r)1mf^l+ZYO6(yq{)9yrX7@UNAhP%uvgS`G-tWQH={u?;GxchwUNGlVXQo4IcP^_=+z9pU>ro98EP4xnT#9AnQ=SdVsOhF;Ck3&t|)%uvhl z%w+5(XU4^7M`q~N4833+Or05O8J?Mphm$j71KN=pdNo5Y7`}sNhFXSaDB}_2%(w*Y z$PB%jp%;wh)S01{;hD+s|G{KN8|}ypy_%sH4Byo=LoLHIlkrG$W{ja7nW0xR^n$U1 zIy2NVJTn=OB4@^>Xh&w~)eOC0_)ec0Y8jrHj7O6*V*>5S485A67mUNHGea%IGn4Tc za%OBoJ2FGBX6Oau2v@EKBDH(;UR>iIuOoY{bMEn8i|d!%NZbLEk;7 zJ%7FEdv9u=_t=AdABwiGbN0OtIXwHm3~dj6`>N+PUOc;}p#S=}-jL;Iaw>5<;dASJ zd{!@~?jszr_7&8#gx5Ilz8*$)U(UI&)5zhuuUDeom%jT_&nNWa8GIFWJlo;DI(c$t z&~jWW=X7#-a$bYBr@kEZg2s#cUxU7@y8koqJO}UJ`MB5DQqL03$Gz^Lb`Q?EhqdJJ z+{5e8?m^!@s1KO)df)Fe(RUDjw@xDBGk-m`&yw@rqxZa%EYCT4XOY8`_Xe~)eR=8w z8!!6a7yT(hp5Kc&-#1b(Bpk8!P1NqeYn*ovyU6arIrnfjIXw69X0&_IcMod&_RgVq z&-X*$Nz{9I3tk`Lh&{ZO+C6xU^X}n#vU_mOJ)A=h&po^iEl=M)gpNHt1^?~DEa4uW zL9A_lliopn3*mft?`*tNi`V;}oJ;+WgzKG;@5#HU2MCAvAnV=4Ea5fIdk;5|y$9#K zhx5qcc@OVFyI+0pLA|K)mUBw)rMAEMe8O|i=PCDnM0}6d@-5SQKjCNRH9p6#aX&Yb z-H-F`=K^wg?&kw&_oMHA)QcN0_HiNlEkx`im>AXC-GH)WwbYA8%zr@3)R(C~r163|iuOBl24U}bhVG=6>3n8B z0xi>dnU|2mlj(Org}x=1#=wj?^VtG9G*<)GxJesna<0+ zlpLPS&!c7P%TyoMc)@%i`t^jrH={&+o?oDr>3lxhN26srFLQz%p3E)y7TM6f%P53+eSh76lSsbeGuB`Sl)?5yf=J>l*p zgL-A-Mc)UbKSR{_{B68h!ueMb@*YRFw{!BYB!?&OJ7{_O^3+E+o}Z~_{1C!t-@b9b z-=+4QnKXC5|3vNmy54#DYWdE|zlt25{C`Hv*O#we)p*{o&(tLGTEgemXDFVl?@{|) zIsZQ5<%G<~lVv(Da|<~CtUODCQf74v!5nTZ|ZBP&*GVQ61k6X+(G;a^&|2SylA^B450YK>lAa~Im*&-|?F OpCapability Int64 +10c11,12 +< OpExecutionMode %main LocalSize 1 1 1 +--- +> ; should ignore this if working with WorkGroupSize builtin +> OpExecutionMode %main LocalSize 2 3 4 +376c378 +< %int = OpTypeInt 32 1 +--- +> %int = OpTypeInt 64 1 +380c382,383 +< %uint = OpTypeInt 32 0 +--- +> %uint_orig = OpTypeInt 32 0 +> %uint = OpTypeInt 64 0 +422a426 +> %uint_orig_1 = OpConstant %uint 1 +587,589c591,594 +< %249 = OpSpecConstant %uint 1 +< %v3uint = OpTypeVector %uint 3 +< %gl_WorkGroupSize = OpSpecConstantComposite %v3uint %249 %uint_1 %uint_1 +--- +> ; default value should be respected, even if no compiler write things other than 1 +> %249 = OpSpecConstant %uint_orig 4 +> %v3uint_orig = OpTypeVector %uint_orig 3 +> %gl_WorkGroupSize = OpSpecConstantComposite %v3uint_orig %249 %uint_orig_1 %uint_orig_1 diff --git a/tests/spec_constant/test_convert.glsl b/tests/spec_constant/test_convert.glsl new file mode 100644 index 00000000..50902d69 --- /dev/null +++ b/tests/spec_constant/test_convert.glsl @@ -0,0 +1,33 @@ +#version 450 + +#extension GL_EXT_shader_explicit_arithmetic_types_int64: enable + +layout(local_size_x = 1) in; + +layout(constant_id = 0) const int64_t SONE = 1; +layout(constant_id = 1) const uint64_t UONE = 1; +layout(constant_id = 2) const double DZERO = 0; + +const uint U_SONE = uint(SONE); +const uint U_UONE = uint(UONE); + +const int S_SONE = int(SONE); +const int S_UONE = int(UONE); + +const float FZERO = float(DZERO); +const double DZERO2 = double(FZERO); + +#define DUMMY_SSBO(name, bind, size) layout(std430, set = 0, binding = bind) buffer SSBO_##name { float val[size]; float dummy; } name + +DUMMY_SSBO(U_Sone, 0, U_SONE); +DUMMY_SSBO(U_Uone, 1, U_UONE); +DUMMY_SSBO(S_Sone, 2, S_SONE); +DUMMY_SSBO(S_Uone, 3, S_UONE); + +void main() +{ + U_Sone.val[0] = FZERO; + U_Uone.val[0] = FZERO; + S_Sone.val[0] = FZERO; + S_Uone.val[0] = FZERO; +} \ No newline at end of file diff --git a/tests/spec_constant/test_convert.spv b/tests/spec_constant/test_convert.spv new file mode 100644 index 0000000000000000000000000000000000000000..20deb2315255e7213f19607773290d1873bddd56 GIT binary patch literal 2064 zcmZ9N+iO!n5XQH;G_AFlSlfE3HMQPbgOpeVL8=(zLoi@0h%bkb9O!{0#^kivxBhMZ zRlW#*zs;GtWMP>7zMY-R&g3MY+bg-^oO7<^%1@-U$}Z<%(AP4(B)#P3J>O`yo7G9$ ztJYq<6zx`A9_7zg-J&aMpOXwa$q>FEnU|C#3z9V<&dUZqjrvJ9Nu$mS3F)8{_ws2rInqpswW=W(zu9Ad5O)?MjcopR28Q@d^H ziey9f_oR;{yu+dT3l3)hn;mf#2@712Mz~Yc9rnZ=OSrqA-PzTiRa4dY;J1G%!Iraa z*)d<_!`Y57b7NdZm|EeGHyLK0z{IIY+xt=5L*ZiywXkQlY>_Lm_%=+WIU|Ok_s1Fa zJ(WI|uZVV8hv*5tITFXL<|Hiq{So5-@tyq8uPsSILhq5c mvV!Bj+1wZAeM1|#(B_eFX~qUFv^fx_&d?7WHh)#!Yso)X(Ug|} literal 0 HcmV?d00001 diff --git a/tests/spec_constant/test_convert.spv.dis b/tests/spec_constant/test_convert.spv.dis new file mode 100644 index 00000000..2895dabe --- /dev/null +++ b/tests/spec_constant/test_convert.spv.dis @@ -0,0 +1,123 @@ +; SPIR-V +; Version: 1.5 +; Generator: Google Shaderc over Glslang; 10 +; Bound: 49 +; Schema: 0 + OpCapability Shader + OpCapability Float64 + OpCapability Int64 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %U_Sone %U_Uone %S_Sone %S_Uone + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpSourceExtension "GL_EXT_shader_explicit_arithmetic_types_int64" + OpSourceExtension "GL_GOOGLE_cpp_style_line_directive" + OpSourceExtension "GL_GOOGLE_include_directive" + OpName %main "main" + OpName %SONE "SONE" + OpName %U_SONE "U_SONE" + OpName %SSBO_U_Sone "SSBO_U_Sone" + OpMemberName %SSBO_U_Sone 0 "val" + OpMemberName %SSBO_U_Sone 1 "dummy" + OpName %U_Sone "U_Sone" + OpName %DZERO "DZERO" + OpName %9999 "FZERO" + OpName %UONE "UONE" + OpName %U_UONE "U_UONE" + OpName %SSBO_U_Uone "SSBO_U_Uone" + OpMemberName %SSBO_U_Uone 0 "val" + OpMemberName %SSBO_U_Uone 1 "dummy" + OpName %U_Uone "U_Uone" + OpName %S_SONE "S_SONE" + OpName %SSBO_S_Sone "SSBO_S_Sone" + OpMemberName %SSBO_S_Sone 0 "val" + OpMemberName %SSBO_S_Sone 1 "dummy" + OpName %S_Sone "S_Sone" + OpName %S_UONE "S_UONE" + OpName %SSBO_S_Uone "SSBO_S_Uone" + OpMemberName %SSBO_S_Uone 0 "val" + OpMemberName %SSBO_S_Uone 1 "dummy" + OpName %S_Uone "S_Uone" + OpName %10000 "DZERO2" + OpDecorate %SONE SpecId 0 + OpDecorate %_arr_float_U_SONE ArrayStride 4 + OpMemberDecorate %SSBO_U_Sone 0 Offset 0 + OpMemberDecorate %SSBO_U_Sone 1 Offset 4 + OpDecorate %SSBO_U_Sone Block + OpDecorate %U_Sone DescriptorSet 0 + OpDecorate %U_Sone Binding 0 + OpDecorate %DZERO SpecId 2 + OpDecorate %UONE SpecId 1 + OpDecorate %_arr_float_U_UONE ArrayStride 4 + OpMemberDecorate %SSBO_U_Uone 0 Offset 0 + OpMemberDecorate %SSBO_U_Uone 1 Offset 4 + OpDecorate %SSBO_U_Uone Block + OpDecorate %U_Uone DescriptorSet 0 + OpDecorate %U_Uone Binding 1 + OpDecorate %_arr_float_S_SONE ArrayStride 4 + OpMemberDecorate %SSBO_S_Sone 0 Offset 0 + OpMemberDecorate %SSBO_S_Sone 1 Offset 4 + OpDecorate %SSBO_S_Sone Block + OpDecorate %S_Sone DescriptorSet 0 + OpDecorate %S_Sone Binding 2 + OpDecorate %_arr_float_S_UONE ArrayStride 4 + OpMemberDecorate %SSBO_S_Uone 0 Offset 0 + OpMemberDecorate %SSBO_S_Uone 1 Offset 4 + OpDecorate %SSBO_S_Uone Block + OpDecorate %S_Uone DescriptorSet 0 + OpDecorate %S_Uone Binding 3 + OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %long = OpTypeInt 64 1 + %SONE = OpSpecConstant %long 1 + %uint = OpTypeInt 32 0 + %int = OpTypeInt 32 1 + %11 = OpSpecConstantOp %int SConvert %SONE + %uint_0 = OpConstant %uint 0 + %U_SONE = OpSpecConstantOp %uint IAdd %11 %uint_0 +%_arr_float_U_SONE = OpTypeArray %float %U_SONE +%SSBO_U_Sone = OpTypeStruct %_arr_float_U_SONE %float +%_ptr_StorageBuffer_SSBO_U_Sone = OpTypePointer StorageBuffer %SSBO_U_Sone + %U_Sone = OpVariable %_ptr_StorageBuffer_SSBO_U_Sone StorageBuffer + %int_0 = OpConstant %int 0 + %double = OpTypeFloat 64 + %DZERO = OpSpecConstant %double 0 + %9999 = OpSpecConstantOp %float FConvert %DZERO +%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float + %ulong = OpTypeInt 64 0 + %UONE = OpSpecConstant %ulong 1 + %U_UONE = OpSpecConstantOp %uint UConvert %UONE +%_arr_float_U_UONE = OpTypeArray %float %U_UONE +%SSBO_U_Uone = OpTypeStruct %_arr_float_U_UONE %float +%_ptr_StorageBuffer_SSBO_U_Uone = OpTypePointer StorageBuffer %SSBO_U_Uone + %U_Uone = OpVariable %_ptr_StorageBuffer_SSBO_U_Uone StorageBuffer + %S_SONE = OpSpecConstantOp %int SConvert %SONE +%_arr_float_S_SONE = OpTypeArray %float %S_SONE +%SSBO_S_Sone = OpTypeStruct %_arr_float_S_SONE %float +%_ptr_StorageBuffer_SSBO_S_Sone = OpTypePointer StorageBuffer %SSBO_S_Sone + %S_Sone = OpVariable %_ptr_StorageBuffer_SSBO_S_Sone StorageBuffer + %38 = OpSpecConstantOp %uint UConvert %UONE + %S_UONE = OpSpecConstantOp %int IAdd %38 %uint_0 +%_arr_float_S_UONE = OpTypeArray %float %S_UONE +%SSBO_S_Uone = OpTypeStruct %_arr_float_S_UONE %float +%_ptr_StorageBuffer_SSBO_S_Uone = OpTypePointer StorageBuffer %SSBO_S_Uone + %S_Uone = OpVariable %_ptr_StorageBuffer_SSBO_S_Uone StorageBuffer + %v3uint = OpTypeVector %uint 3 + %uint_1 = OpConstant %uint 1 +%gl_WorkGroupSize = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1 + %10000 = OpSpecConstantOp %double FConvert %9999 + %main = OpFunction %void None %3 + %5 = OpLabel + %23 = OpAccessChain %_ptr_StorageBuffer_float %U_Sone %int_0 %int_0 + OpStore %23 %9999 + %31 = OpAccessChain %_ptr_StorageBuffer_float %U_Uone %int_0 %int_0 + OpStore %31 %9999 + %37 = OpAccessChain %_ptr_StorageBuffer_float %S_Sone %int_0 %int_0 + OpStore %37 %9999 + %44 = OpAccessChain %_ptr_StorageBuffer_float %S_Uone %int_0 %int_0 + OpStore %44 %9999 + OpReturn + OpFunctionEnd diff --git a/tests/spec_constant/test_convert.spv.dis.patch b/tests/spec_constant/test_convert.spv.dis.patch new file mode 100644 index 00000000..bb954b1f --- /dev/null +++ b/tests/spec_constant/test_convert.spv.dis.patch @@ -0,0 +1,32 @@ +25c25 +< OpName %FZERO "FZERO" +--- +> OpName %9999 "FZERO" +42c42 +< OpName %DZERO2 "DZERO2" +--- +> OpName %10000 "DZERO2" +88c88 +< %FZERO = OpSpecConstantOp %float FConvert %DZERO +--- +> %9999 = OpSpecConstantOp %float FConvert %DZERO +111c111 +< %DZERO2 = OpSpecConstantOp %double FConvert %FZERO +--- +> %10000 = OpSpecConstantOp %double FConvert %9999 +115c115 +< OpStore %23 %FZERO +--- +> OpStore %23 %9999 +117c117 +< OpStore %31 %FZERO +--- +> OpStore %31 %9999 +119c119 +< OpStore %37 %FZERO +--- +> OpStore %37 %9999 +121c121 +< OpStore %44 %FZERO +--- +> OpStore %44 %9999 diff --git a/tests/spec_constant/test_localsizeid.spv b/tests/spec_constant/test_localsizeid.spv new file mode 100644 index 0000000000000000000000000000000000000000..98c9333d0f54f96c07238674d5a89aef71de333a GIT binary patch literal 11444 zcmZ9Q2bfjW6-Hl}89)&bL2O76(Ije&8Z<_YGKO&&eax77j1prUkQtF=0HZ)+icXBt zm|jgaUDJE-iRr!f-h1!WtaaYqusP@ZwrBtU*>|sV&%5u<#hw{Q&T94Dsnu%DYW;`* zIu^8Mv~=dQW|n!d-Dw|x)sBhdSDt)=>+@PYPGxO=YelP%dsaP)-_FiU$?dD>h`#E&ub=Bs_ma~0IQ81GHdE<)cjj*2wL7QC?W^aAzUsQK&&p8u zlG68h^w{d53z$mZdoY*2W2?99BDb%eBl@cAzCM4=C8duKaA$a6a6Fy)iF%23lG-!x z>|yCSf~BrmKIhFPg>_GL=`%XHmE1k+Iiioc?&Ei*)4inhS*b32UNbttljY}ovfkQ} z-OtG>>cU#PJ)RRiN3hg2%kN~Tdr9egFZ5XId#da99oy4a&k=pqbzi^d%_XJpz0vK? zn%&RIY3S0o-MKuT6Fo=tRo8v}?PxA3eNRV^roLyOOW)Bwef1pCS6%nr53jkT^u15f zYxORYto;-T0_wLzSeuIa)m(ZoBbzf@6+UrVB zAF|SOY-$H-=~*5;^607FyJt`NP4^P}`GYvt9w`0JA#eIkl9qmYj_9YZ`z^p5o0=^B z2F(Y%`&&ca?YDXN{`4HtPhI!(Z_OB&xW6Iu!S4RfC2#ue-k+W$`l;)F{@ohe+}+=K z^_?H_%Jm-&*tL{D#fTcb&sv_!;XtqMy3%=ik##bAJ9o z>NMwfzIo}l=lt{>(NA6XTa4Ff&d&$1)12R^dAHy0{pmTPpSten-}z2+ejW1m$Y^<9 z*6G`?z5Pnka=&_x=%=px`Oe@aeow~C`-jV8+lO-jy4!Q(wh402P|p!P)qD5sE$<-h z?j@z~h19f%N6L2WyB^)`yKVapa{KBzqOZE{>w8VRdkI~7TK7l0U3*?cUV8SIt(Km8 zj_9f0yJt^%Px2D`J%DwNlf1WeF?s1Xa%JhIc0@0A-D?RR<)zmH$=5fZ%_Zce*ZMu5 zjh-X=sq22eyLpLw8z=V&z1I!orQdKlzOp|(NA%l3UiVvy=Oy;rNZxLKV|}+N{o3W{ zu=LY&L_c-i&v!~M@w_&fr{7qgmu}B(yMJT#9MMy~chBC|GQ4*8lCn>~9G!tSd0*=? z^YWdUoFXmz)N@2n_1-;u$~$j|OWfyX*4K@W4S0?Ea^`dT+Z~NT^a^ILpV8=}8tuEH z>qj@buhG7nT0gVVTbjI=c@2bk4?Pm?2+wQutQ+L>ur8RgmJ<${>LZHk>Iad_3r4(? zW=6c1W`ect97fjz_GgB=y7~9A*Bi?5-Bi?EAedz^b zHhE^KWyEv0lH5JY_CB{WXXYtrM`r5P_oWxieaJIYEz`a-u4r=a)93h9W=Ce|)eOC0 z>`R^*Y8i1K-S@FQ&-Q7oIWj}9X6OZD4tZv%Wq5|(2S3q!oz)p=M`q~N4836NN1hpK z8J?MptC;iWaVFZ48G1ECFBo&lGea%IGn3K%+qvhgR^dA`V->n)=mldQd1k0(cxEzo zGUxj^8|}ypy_%sngRsYZ=H-MVv<%Noy^A?BR-+x6p;t5Xg0Vk&W~gO&W-=bioEhh! z9hsq5GxUPtyLD!$Wq4*X9>$y*YtW9&(5o4G!8m|CGt@FXLmB?Ri_AC|?Z^zhnxPkr zh2)u`mf@MncsO%rw9$^t(5o4G!B|9|8EP4xnT$s;XT~tvkr{e5LoXPmg>LoLHIlkq6#%os&GGDELs=mo=f`pi(v@XTaf!<-rG(2mT| zs~LL1IG8*$)G|CX8P_sr#sz3cX6V%nyBF=xibXh&w~)eOC0EFsSfb!I#Uof(&) z9hsq5GxUPtzaKI~of+4oGh+kVkr^A%HA62LOUW}sEyK^=vwAFZW?YJPWQJbN(3?Tn z!+&QiCmf+=_}Qy(V9tyQv?DY0YKC4gmXT+MT85v!j2oFV<1(}(GxTbPUNG#J8EV7N zUWRL4AMYuf8_iVKFK@Ip3+ehe<|BC1y@}a;G5O<}mk|fj?+HzA{Yi~pL7w$dX!p00 zyR-g@#57@@Yxa2(^D@G5Y@?stmE}6upF&I%UhkSb{i6wa_E$fZm?o@uE$Z$<9{aHF zuEaE9y=%dJ8oBSl(eLTx*Adpcwgm1LX3xR3rRcjchqny<4D^14{^^bGX*@Ze!!rqo z+Fs8p%5&&#-AwNF`mv8^lTQ;X2=71qW60f~_h60tdl0kNy5|0lWe(5&&q3Q?-~Fk3 z8!!4EhrXV$Z$6*rqP>@>dmg!b>s^!oU}pKQ$-g^uc=Df*mai{g?V0OE-{Z+|AcAk- zDYSiEv+q5a!?W)T(Du-`uX<+V#q)Ur`hR!aafh5Ike^80Ncb$e7N5^8%_d;Tt zu--NIvz6KXxaNLNVh+#!ya?@n^xcnoR^!F<=J(s@*M8fW?WbqIdoqV-zZawJr*A*? zY@*BPK36Nz|4sLIGTQxnf3C%Szl406a6Rs4JGp$<=^7ZAb?Wq@iPba^fsQItNn~~~XMK0fZ*W_QxEZ;Tx zXE28+|J7(&`tm~u-_P|m#55uQ$;3*&N&2rPt|43x?{$smGwlAYyASbU!g|-^`F}lm zFA;TbAfG0zcg_7@#q9oFbN^>Dhv)v^h<2~~?q5B(@fLA9Zz8w9^I3%Vm(S7ty_xX) zv663&`YnX#Wxda>>+WR-vwLyfy{uvm&%L}A?OycVi+UcR7klU@_q<{c!F(H@OxNYb z_hl!!OxI zb(w3J!;|@5v`l@O>H``tm_ulv)tdP}JejU%=GADKuFE`^IXs!~N6XZgsb1K4!8{M` z^L#R4?|6njKrYku%zQXnrt31>%;CxWAX=urO!Xo{FPLk|eeP@Khwx;&o|%t8%XD4l zFmre^Z%5l-U#9xN#tY^M+TV+s>2HZl*Yh* zP0jo$o=n#>^HFG-uFD){4o~LC&@%O9st;zKon`3ba4eVOWm8!wn+=vNRm^OJZoUC;MC00e+IZgMlgRH+ct(CVjqpE9ejVZZ z(+GdtAI)rU*W_Kq9G<+-q2=kzQyVydGeV=)O~?mzV)ujSIc)z z{>9AU$^Rl+zP^0*lE#a^4@CQX)%W`)ylKMqBMEtrVV38byi1tFllNt`JbiiU!yC`f z)AJoCK0(+w?)59=@$PHQR|)UKTGwP>&n(+D*&CR{ll?WcY<=14rG%dM>a(a!Ei)7Qy;o?Or0na84Kx-Rol=I~^G18skOnd&aUEIX{kh2I07g_y_7c%>8^0H#2{i=pmlj#F;3)XAx2J zJ#sm@MlaWVAKh2g=;fLppl4P!db#F@=vh^bUat8OdUjQ#mur5E-lwY3%QZhi?_1UA z<(i+O=TtR%x#nkRKdXE`db#H3=($ymUat8CdR|qdmur5Bo?q4I<(gli_pfU7a?P*N z3#uBuT=N_B0acA&uK6u`VO67-Ykr4bRMqI^n%|=jtZMXf%^%Q OpExecutionModeId %main LocalSizeId %249 %uint_1 %uint_1 +370d369 +< OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize +587,589c586,587 +< %249 = OpSpecConstant %uint 1 +< %v3uint = OpTypeVector %uint 3 +< %gl_WorkGroupSize = OpSpecConstantComposite %v3uint %249 %uint_1 %uint_1 +--- +> ; default value should be respected, even if no compiler write things other than 1 +> %249 = OpSpecConstant %uint 4 diff --git a/tests/spec_constant/test_orig.glsl b/tests/spec_constant/test_orig.glsl new file mode 100644 index 00000000..265c890b --- /dev/null +++ b/tests/spec_constant/test_orig.glsl @@ -0,0 +1,123 @@ +#version 450 + +layout(local_size_x_id = 8) in; + +layout(constant_id = 0) const bool TRUE = true; +layout(constant_id = 1) const bool FALSE = false; +layout(constant_id = 2) const int SONE = 1; +layout(constant_id = 3) const int STWO = 2; +layout(constant_id = 4) const int SNEG_TWO = -2; +layout(constant_id = 5) const uint UONE = 1; +layout(constant_id = 6) const uint UTWO = 2; +layout(constant_id = 7) const int SNEG_THREE = -3; + +const uint IADD = SONE + STWO + UONE + UTWO; // 6 +const uint ISUB = UTWO - SONE; // 1 +const uint IMUL = UTWO * UTWO; // 4 +const uint UDIV = UTWO / UTWO; // 1 +const int SDIV = STWO / SNEG_TWO; // -1 +//const int SREM = STWO % SNEG_THREE; // 1 +const int SREM = 1; +const int SMOD = STWO % SNEG_THREE; // -1 +const uint UMOD = IADD % IMUL; // 2 + +const uint LSHL = IADD << ISUB; // 12 +const uint RSHL = IADD >> ISUB; // 3 +const int RSHA = (-int(IADD)) >> (-SDIV); // -3 + +const bool IEQ = IADD == ISUB; // false +const bool INEQ = IADD != ISUB; // true +const bool ULT = IADD < ISUB; // false +const bool ULE = IADD <= ISUB; // false +const bool UGT = IADD > ISUB; // true +const bool UGE = IADD >= ISUB; // true + +const bool SLT = SMOD < SREM; // true +const bool SLE = SMOD <= SREM; // true +const bool SGT = SMOD > SREM; // false +const bool SGE = SMOD >= SREM; // false + +const bool LOR = IEQ || SLT; // true +const bool LAND = IEQ && SLT; // false +const bool LNOT = !LOR; // false + +const uint AND = IADD & IADD; // 6 +const uint OR = IADD | ISUB; // 7 +const uint XOR = IADD ^ IADD; // 0 +const uint NOT = ~XOR; // UINT_MAX + +const bool LEQ = LAND == LNOT; // true +const bool LNEQ = LAND != LNOT; // false + +const uint SEL = IEQ ? IADD : ISUB; // 1 + +#define DUMMY_SSBO(name, bind, size) layout(std430, set = 0, binding = bind) buffer SSBO_##name { float val[size]; float dummy; } name + +// Normalize all sizes to 1 element so that the default offsets in glslang matches up with what we should be computing. +// If we do it right, we should get no layout(offset = N) expressions. +DUMMY_SSBO(IAdd, 0, IADD - 5); +DUMMY_SSBO(ISub, 1, ISUB); +DUMMY_SSBO(IMul, 2, IMUL - 3); +DUMMY_SSBO(UDiv, 3, UDIV); +DUMMY_SSBO(SDiv, 4, SDIV + 2); +DUMMY_SSBO(SRem, 5, SREM); +DUMMY_SSBO(SMod, 6, SMOD + 2); +DUMMY_SSBO(UMod, 7, UMOD - 1); +DUMMY_SSBO(LShl, 8, LSHL - 11); +DUMMY_SSBO(RShl, 9, RSHL - 2); +DUMMY_SSBO(RSha, 10, RSHA + 4); +DUMMY_SSBO(IEq, 11, IEQ ? 2 : 1); +DUMMY_SSBO(INeq, 12, INEQ ? 1 : 2); +DUMMY_SSBO(Ult, 13, ULT ? 2 : 1); +DUMMY_SSBO(Ule, 14, ULE ? 2 : 1); +DUMMY_SSBO(Ugt, 15, UGT ? 1 : 2); +DUMMY_SSBO(Uge, 16, UGE ? 1 : 2); +DUMMY_SSBO(Slt, 17, SLT ? 1 : 2); +DUMMY_SSBO(Sle, 18, SLE ? 1 : 2); +DUMMY_SSBO(Sgt, 19, SGT ? 2 : 1); +DUMMY_SSBO(Sge, 20, SGE ? 2 : 1); +DUMMY_SSBO(Lor, 21, LOR ? 1 : 2); +DUMMY_SSBO(Land, 22, LAND ? 2 : 1); +DUMMY_SSBO(Lnot, 23, LNOT ? 2 : 1); +DUMMY_SSBO(And, 24, AND - 5); +DUMMY_SSBO(Or, 24, OR - 6); +DUMMY_SSBO(Xor, 24, XOR + 1); +DUMMY_SSBO(Not, 25, NOT - 0xfffffffeu); +DUMMY_SSBO(Leq, 26, LEQ ? 1 : 2); +DUMMY_SSBO(Lneq, 27, LNEQ ? 2 : 1); +DUMMY_SSBO(Sel, 28, SEL); + +void main() +{ + IAdd.val[0] = 0.0; + ISub.val[0] = 0.0; + IMul.val[0] = 0.0; + UDiv.val[0] = 0.0; + SDiv.val[0] = 0.0; + SRem.val[0] = 0.0; + SMod.val[0] = 0.0; + UMod.val[0] = 0.0; + LShl.val[0] = 0.0; + RShl.val[0] = 0.0; + RSha.val[0] = 0.0; + IEq.val[0] = 0.0; + INeq.val[0] = 0.0; + Ult.val[0] = 0.0; + Ule.val[0] = 0.0; + Ugt.val[0] = 0.0; + Uge.val[0] = 0.0; + Slt.val[0] = 0.0; + Sle.val[0] = 0.0; + Sgt.val[0] = 0.0; + Sge.val[0] = 0.0; + Lor.val[0] = 0.0; + Land.val[0] = 0.0; + Lnot.val[0] = 0.0; + And.val[0] = 0.0; + Or.val[0] = 0.0; + Xor.val[0] = 0.0; + Not.val[0] = 0.0; + Leq.val[0] = 0.0; + Lneq.val[0] = 0.0; + Sel.val[0] = 0.0; +} \ No newline at end of file diff --git a/tests/spec_constant/test_orig.spv.dis b/tests/spec_constant/test_orig.spv.dis new file mode 100644 index 00000000..118b8b07 --- /dev/null +++ b/tests/spec_constant/test_orig.spv.dis @@ -0,0 +1,657 @@ +; SPIR-V +; Version: 1.5 +; Generator: Google Shaderc over Glslang; 10 +; Bound: 254 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %IAdd %ISub %IMul %UDiv %SDiv %SRem %SMod %UMod %LShl %RShl %RSha %IEq %INeq %Ult %Ule %Ugt %Uge %Slt %Sle %Sgt %Sge %Lor %Land %Lnot %And %Or %Xor %Not %Leq %Lneq %Sel + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpSourceExtension "GL_GOOGLE_cpp_style_line_directive" + OpSourceExtension "GL_GOOGLE_include_directive" + OpName %main "main" + OpName %SONE "SONE" + OpName %STWO "STWO" + OpName %UONE "UONE" + OpName %UTWO "UTWO" + OpName %IADD "IADD" + OpName %SSBO_IAdd "SSBO_IAdd" + OpMemberName %SSBO_IAdd 0 "val" + OpMemberName %SSBO_IAdd 1 "dummy" + OpName %IAdd "IAdd" + OpName %ISUB "ISUB" + OpName %SSBO_ISub "SSBO_ISub" + OpMemberName %SSBO_ISub 0 "val" + OpMemberName %SSBO_ISub 1 "dummy" + OpName %ISub "ISub" + OpName %IMUL "IMUL" + OpName %SSBO_IMul "SSBO_IMul" + OpMemberName %SSBO_IMul 0 "val" + OpMemberName %SSBO_IMul 1 "dummy" + OpName %IMul "IMul" + OpName %UDIV "UDIV" + OpName %SSBO_UDiv "SSBO_UDiv" + OpMemberName %SSBO_UDiv 0 "val" + OpMemberName %SSBO_UDiv 1 "dummy" + OpName %UDiv "UDiv" + OpName %SNEG_TWO "SNEG_TWO" + OpName %SDIV "SDIV" + OpName %SSBO_SDiv "SSBO_SDiv" + OpMemberName %SSBO_SDiv 0 "val" + OpMemberName %SSBO_SDiv 1 "dummy" + OpName %SDiv "SDiv" + OpName %SSBO_SRem "SSBO_SRem" + OpMemberName %SSBO_SRem 0 "val" + OpMemberName %SSBO_SRem 1 "dummy" + OpName %SRem "SRem" + OpName %SNEG_THREE "SNEG_THREE" + OpName %SMOD "SMOD" + OpName %SSBO_SMod "SSBO_SMod" + OpMemberName %SSBO_SMod 0 "val" + OpMemberName %SSBO_SMod 1 "dummy" + OpName %SMod "SMod" + OpName %UMOD "UMOD" + OpName %SSBO_UMod "SSBO_UMod" + OpMemberName %SSBO_UMod 0 "val" + OpMemberName %SSBO_UMod 1 "dummy" + OpName %UMod "UMod" + OpName %LSHL "LSHL" + OpName %SSBO_LShl "SSBO_LShl" + OpMemberName %SSBO_LShl 0 "val" + OpMemberName %SSBO_LShl 1 "dummy" + OpName %LShl "LShl" + OpName %RSHL "RSHL" + OpName %SSBO_RShl "SSBO_RShl" + OpMemberName %SSBO_RShl 0 "val" + OpMemberName %SSBO_RShl 1 "dummy" + OpName %RShl "RShl" + OpName %RSHA "RSHA" + OpName %SSBO_RSha "SSBO_RSha" + OpMemberName %SSBO_RSha 0 "val" + OpMemberName %SSBO_RSha 1 "dummy" + OpName %RSha "RSha" + OpName %IEQ "IEQ" + OpName %SSBO_IEq "SSBO_IEq" + OpMemberName %SSBO_IEq 0 "val" + OpMemberName %SSBO_IEq 1 "dummy" + OpName %IEq "IEq" + OpName %INEQ "INEQ" + OpName %SSBO_INeq "SSBO_INeq" + OpMemberName %SSBO_INeq 0 "val" + OpMemberName %SSBO_INeq 1 "dummy" + OpName %INeq "INeq" + OpName %ULT "ULT" + OpName %SSBO_Ult "SSBO_Ult" + OpMemberName %SSBO_Ult 0 "val" + OpMemberName %SSBO_Ult 1 "dummy" + OpName %Ult "Ult" + OpName %ULE "ULE" + OpName %SSBO_Ule "SSBO_Ule" + OpMemberName %SSBO_Ule 0 "val" + OpMemberName %SSBO_Ule 1 "dummy" + OpName %Ule "Ule" + OpName %UGT "UGT" + OpName %SSBO_Ugt "SSBO_Ugt" + OpMemberName %SSBO_Ugt 0 "val" + OpMemberName %SSBO_Ugt 1 "dummy" + OpName %Ugt "Ugt" + OpName %UGE "UGE" + OpName %SSBO_Uge "SSBO_Uge" + OpMemberName %SSBO_Uge 0 "val" + OpMemberName %SSBO_Uge 1 "dummy" + OpName %Uge "Uge" + OpName %SLT "SLT" + OpName %SSBO_Slt "SSBO_Slt" + OpMemberName %SSBO_Slt 0 "val" + OpMemberName %SSBO_Slt 1 "dummy" + OpName %Slt "Slt" + OpName %SLE "SLE" + OpName %SSBO_Sle "SSBO_Sle" + OpMemberName %SSBO_Sle 0 "val" + OpMemberName %SSBO_Sle 1 "dummy" + OpName %Sle "Sle" + OpName %SGT "SGT" + OpName %SSBO_Sgt "SSBO_Sgt" + OpMemberName %SSBO_Sgt 0 "val" + OpMemberName %SSBO_Sgt 1 "dummy" + OpName %Sgt "Sgt" + OpName %SGE "SGE" + OpName %SSBO_Sge "SSBO_Sge" + OpMemberName %SSBO_Sge 0 "val" + OpMemberName %SSBO_Sge 1 "dummy" + OpName %Sge "Sge" + OpName %LOR "LOR" + OpName %SSBO_Lor "SSBO_Lor" + OpMemberName %SSBO_Lor 0 "val" + OpMemberName %SSBO_Lor 1 "dummy" + OpName %Lor "Lor" + OpName %LAND "LAND" + OpName %SSBO_Land "SSBO_Land" + OpMemberName %SSBO_Land 0 "val" + OpMemberName %SSBO_Land 1 "dummy" + OpName %Land "Land" + OpName %LNOT "LNOT" + OpName %SSBO_Lnot "SSBO_Lnot" + OpMemberName %SSBO_Lnot 0 "val" + OpMemberName %SSBO_Lnot 1 "dummy" + OpName %Lnot "Lnot" + OpName %AND "AND" + OpName %SSBO_And "SSBO_And" + OpMemberName %SSBO_And 0 "val" + OpMemberName %SSBO_And 1 "dummy" + OpName %And "And" + OpName %OR "OR" + OpName %SSBO_Or "SSBO_Or" + OpMemberName %SSBO_Or 0 "val" + OpMemberName %SSBO_Or 1 "dummy" + OpName %Or "Or" + OpName %XOR "XOR" + OpName %SSBO_Xor "SSBO_Xor" + OpMemberName %SSBO_Xor 0 "val" + OpMemberName %SSBO_Xor 1 "dummy" + OpName %Xor "Xor" + OpName %NOT "NOT" + OpName %SSBO_Not "SSBO_Not" + OpMemberName %SSBO_Not 0 "val" + OpMemberName %SSBO_Not 1 "dummy" + OpName %Not "Not" + OpName %LEQ "LEQ" + OpName %SSBO_Leq "SSBO_Leq" + OpMemberName %SSBO_Leq 0 "val" + OpMemberName %SSBO_Leq 1 "dummy" + OpName %Leq "Leq" + OpName %LNEQ "LNEQ" + OpName %SSBO_Lneq "SSBO_Lneq" + OpMemberName %SSBO_Lneq 0 "val" + OpMemberName %SSBO_Lneq 1 "dummy" + OpName %Lneq "Lneq" + OpName %SEL "SEL" + OpName %SSBO_Sel "SSBO_Sel" + OpMemberName %SSBO_Sel 0 "val" + OpMemberName %SSBO_Sel 1 "dummy" + OpName %Sel "Sel" + OpName %TRUE "TRUE" + OpName %FALSE "FALSE" + OpDecorate %SONE SpecId 2 + OpDecorate %STWO SpecId 3 + OpDecorate %UONE SpecId 5 + OpDecorate %UTWO SpecId 6 + OpDecorate %_arr_float_19 ArrayStride 4 + OpMemberDecorate %SSBO_IAdd 0 Offset 0 + OpMemberDecorate %SSBO_IAdd 1 Offset 4 + OpDecorate %SSBO_IAdd Block + OpDecorate %IAdd DescriptorSet 0 + OpDecorate %IAdd Binding 0 + OpDecorate %_arr_float_ISUB ArrayStride 4 + OpMemberDecorate %SSBO_ISub 0 Offset 0 + OpMemberDecorate %SSBO_ISub 1 Offset 4 + OpDecorate %SSBO_ISub Block + OpDecorate %ISub DescriptorSet 0 + OpDecorate %ISub Binding 1 + OpDecorate %_arr_float_37 ArrayStride 4 + OpMemberDecorate %SSBO_IMul 0 Offset 0 + OpMemberDecorate %SSBO_IMul 1 Offset 4 + OpDecorate %SSBO_IMul Block + OpDecorate %IMul DescriptorSet 0 + OpDecorate %IMul Binding 2 + OpDecorate %_arr_float_UDIV ArrayStride 4 + OpMemberDecorate %SSBO_UDiv 0 Offset 0 + OpMemberDecorate %SSBO_UDiv 1 Offset 4 + OpDecorate %SSBO_UDiv Block + OpDecorate %UDiv DescriptorSet 0 + OpDecorate %UDiv Binding 3 + OpDecorate %SNEG_TWO SpecId 4 + OpDecorate %_arr_float_52 ArrayStride 4 + OpMemberDecorate %SSBO_SDiv 0 Offset 0 + OpMemberDecorate %SSBO_SDiv 1 Offset 4 + OpDecorate %SSBO_SDiv Block + OpDecorate %SDiv DescriptorSet 0 + OpDecorate %SDiv Binding 4 + OpDecorate %_arr_float_uint_1 ArrayStride 4 + OpMemberDecorate %SSBO_SRem 0 Offset 0 + OpMemberDecorate %SSBO_SRem 1 Offset 4 + OpDecorate %SSBO_SRem Block + OpDecorate %SRem DescriptorSet 0 + OpDecorate %SRem Binding 5 + OpDecorate %SNEG_THREE SpecId 7 + OpDecorate %_arr_float_66 ArrayStride 4 + OpMemberDecorate %SSBO_SMod 0 Offset 0 + OpMemberDecorate %SSBO_SMod 1 Offset 4 + OpDecorate %SSBO_SMod Block + OpDecorate %SMod DescriptorSet 0 + OpDecorate %SMod Binding 6 + OpDecorate %_arr_float_73 ArrayStride 4 + OpMemberDecorate %SSBO_UMod 0 Offset 0 + OpMemberDecorate %SSBO_UMod 1 Offset 4 + OpDecorate %SSBO_UMod Block + OpDecorate %UMod DescriptorSet 0 + OpDecorate %UMod Binding 7 + OpDecorate %_arr_float_81 ArrayStride 4 + OpMemberDecorate %SSBO_LShl 0 Offset 0 + OpMemberDecorate %SSBO_LShl 1 Offset 4 + OpDecorate %SSBO_LShl Block + OpDecorate %LShl DescriptorSet 0 + OpDecorate %LShl Binding 8 + OpDecorate %_arr_float_89 ArrayStride 4 + OpMemberDecorate %SSBO_RShl 0 Offset 0 + OpMemberDecorate %SSBO_RShl 1 Offset 4 + OpDecorate %SSBO_RShl Block + OpDecorate %RShl DescriptorSet 0 + OpDecorate %RShl Binding 9 + OpDecorate %_arr_float_100 ArrayStride 4 + OpMemberDecorate %SSBO_RSha 0 Offset 0 + OpMemberDecorate %SSBO_RSha 1 Offset 4 + OpDecorate %SSBO_RSha Block + OpDecorate %RSha DescriptorSet 0 + OpDecorate %RSha Binding 10 + OpDecorate %_arr_float_109 ArrayStride 4 + OpMemberDecorate %SSBO_IEq 0 Offset 0 + OpMemberDecorate %SSBO_IEq 1 Offset 4 + OpDecorate %SSBO_IEq Block + OpDecorate %IEq DescriptorSet 0 + OpDecorate %IEq Binding 11 + OpDecorate %_arr_float_116 ArrayStride 4 + OpMemberDecorate %SSBO_INeq 0 Offset 0 + OpMemberDecorate %SSBO_INeq 1 Offset 4 + OpDecorate %SSBO_INeq Block + OpDecorate %INeq DescriptorSet 0 + OpDecorate %INeq Binding 12 + OpDecorate %_arr_float_123 ArrayStride 4 + OpMemberDecorate %SSBO_Ult 0 Offset 0 + OpMemberDecorate %SSBO_Ult 1 Offset 4 + OpDecorate %SSBO_Ult Block + OpDecorate %Ult DescriptorSet 0 + OpDecorate %Ult Binding 13 + OpDecorate %_arr_float_130 ArrayStride 4 + OpMemberDecorate %SSBO_Ule 0 Offset 0 + OpMemberDecorate %SSBO_Ule 1 Offset 4 + OpDecorate %SSBO_Ule Block + OpDecorate %Ule DescriptorSet 0 + OpDecorate %Ule Binding 14 + OpDecorate %_arr_float_137 ArrayStride 4 + OpMemberDecorate %SSBO_Ugt 0 Offset 0 + OpMemberDecorate %SSBO_Ugt 1 Offset 4 + OpDecorate %SSBO_Ugt Block + OpDecorate %Ugt DescriptorSet 0 + OpDecorate %Ugt Binding 15 + OpDecorate %_arr_float_144 ArrayStride 4 + OpMemberDecorate %SSBO_Uge 0 Offset 0 + OpMemberDecorate %SSBO_Uge 1 Offset 4 + OpDecorate %SSBO_Uge Block + OpDecorate %Uge DescriptorSet 0 + OpDecorate %Uge Binding 16 + OpDecorate %_arr_float_151 ArrayStride 4 + OpMemberDecorate %SSBO_Slt 0 Offset 0 + OpMemberDecorate %SSBO_Slt 1 Offset 4 + OpDecorate %SSBO_Slt Block + OpDecorate %Slt DescriptorSet 0 + OpDecorate %Slt Binding 17 + OpDecorate %_arr_float_158 ArrayStride 4 + OpMemberDecorate %SSBO_Sle 0 Offset 0 + OpMemberDecorate %SSBO_Sle 1 Offset 4 + OpDecorate %SSBO_Sle Block + OpDecorate %Sle DescriptorSet 0 + OpDecorate %Sle Binding 18 + OpDecorate %_arr_float_165 ArrayStride 4 + OpMemberDecorate %SSBO_Sgt 0 Offset 0 + OpMemberDecorate %SSBO_Sgt 1 Offset 4 + OpDecorate %SSBO_Sgt Block + OpDecorate %Sgt DescriptorSet 0 + OpDecorate %Sgt Binding 19 + OpDecorate %_arr_float_172 ArrayStride 4 + OpMemberDecorate %SSBO_Sge 0 Offset 0 + OpMemberDecorate %SSBO_Sge 1 Offset 4 + OpDecorate %SSBO_Sge Block + OpDecorate %Sge DescriptorSet 0 + OpDecorate %Sge Binding 20 + OpDecorate %_arr_float_179 ArrayStride 4 + OpMemberDecorate %SSBO_Lor 0 Offset 0 + OpMemberDecorate %SSBO_Lor 1 Offset 4 + OpDecorate %SSBO_Lor Block + OpDecorate %Lor DescriptorSet 0 + OpDecorate %Lor Binding 21 + OpDecorate %_arr_float_186 ArrayStride 4 + OpMemberDecorate %SSBO_Land 0 Offset 0 + OpMemberDecorate %SSBO_Land 1 Offset 4 + OpDecorate %SSBO_Land Block + OpDecorate %Land DescriptorSet 0 + OpDecorate %Land Binding 22 + OpDecorate %_arr_float_193 ArrayStride 4 + OpMemberDecorate %SSBO_Lnot 0 Offset 0 + OpMemberDecorate %SSBO_Lnot 1 Offset 4 + OpDecorate %SSBO_Lnot Block + OpDecorate %Lnot DescriptorSet 0 + OpDecorate %Lnot Binding 23 + OpDecorate %_arr_float_200 ArrayStride 4 + OpMemberDecorate %SSBO_And 0 Offset 0 + OpMemberDecorate %SSBO_And 1 Offset 4 + OpDecorate %SSBO_And Block + OpDecorate %And DescriptorSet 0 + OpDecorate %And Binding 24 + OpDecorate %_arr_float_208 ArrayStride 4 + OpMemberDecorate %SSBO_Or 0 Offset 0 + OpMemberDecorate %SSBO_Or 1 Offset 4 + OpDecorate %SSBO_Or Block + OpDecorate %Or DescriptorSet 0 + OpDecorate %Or Binding 24 + OpDecorate %_arr_float_215 ArrayStride 4 + OpMemberDecorate %SSBO_Xor 0 Offset 0 + OpMemberDecorate %SSBO_Xor 1 Offset 4 + OpDecorate %SSBO_Xor Block + OpDecorate %Xor DescriptorSet 0 + OpDecorate %Xor Binding 24 + OpDecorate %_arr_float_223 ArrayStride 4 + OpMemberDecorate %SSBO_Not 0 Offset 0 + OpMemberDecorate %SSBO_Not 1 Offset 4 + OpDecorate %SSBO_Not Block + OpDecorate %Not DescriptorSet 0 + OpDecorate %Not Binding 25 + OpDecorate %_arr_float_230 ArrayStride 4 + OpMemberDecorate %SSBO_Leq 0 Offset 0 + OpMemberDecorate %SSBO_Leq 1 Offset 4 + OpDecorate %SSBO_Leq Block + OpDecorate %Leq DescriptorSet 0 + OpDecorate %Leq Binding 26 + OpDecorate %_arr_float_237 ArrayStride 4 + OpMemberDecorate %SSBO_Lneq 0 Offset 0 + OpMemberDecorate %SSBO_Lneq 1 Offset 4 + OpDecorate %SSBO_Lneq Block + OpDecorate %Lneq DescriptorSet 0 + OpDecorate %Lneq Binding 27 + OpDecorate %_arr_float_SEL ArrayStride 4 + OpMemberDecorate %SSBO_Sel 0 Offset 0 + OpMemberDecorate %SSBO_Sel 1 Offset 4 + OpDecorate %SSBO_Sel Block + OpDecorate %Sel DescriptorSet 0 + OpDecorate %Sel Binding 28 + OpDecorate %249 SpecId 8 + OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize + OpDecorate %TRUE SpecId 0 + OpDecorate %FALSE SpecId 1 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %int = OpTypeInt 32 1 + %SONE = OpSpecConstant %int 1 + %STWO = OpSpecConstant %int 2 + %10 = OpSpecConstantOp %int IAdd %SONE %STWO + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %13 = OpSpecConstantOp %uint IAdd %10 %uint_0 + %UONE = OpSpecConstant %uint 1 + %15 = OpSpecConstantOp %uint IAdd %13 %UONE + %UTWO = OpSpecConstant %uint 2 + %IADD = OpSpecConstantOp %uint IAdd %15 %UTWO + %uint_5 = OpConstant %uint 5 + %19 = OpSpecConstantOp %uint ISub %IADD %uint_5 +%_arr_float_19 = OpTypeArray %float %19 + %SSBO_IAdd = OpTypeStruct %_arr_float_19 %float +%_ptr_StorageBuffer_SSBO_IAdd = OpTypePointer StorageBuffer %SSBO_IAdd + %IAdd = OpVariable %_ptr_StorageBuffer_SSBO_IAdd StorageBuffer + %int_0 = OpConstant %int 0 + %float_0 = OpConstant %float 0 +%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float + %28 = OpSpecConstantOp %uint IAdd %SONE %uint_0 + %ISUB = OpSpecConstantOp %uint ISub %UTWO %28 +%_arr_float_ISUB = OpTypeArray %float %ISUB + %SSBO_ISub = OpTypeStruct %_arr_float_ISUB %float +%_ptr_StorageBuffer_SSBO_ISub = OpTypePointer StorageBuffer %SSBO_ISub + %ISub = OpVariable %_ptr_StorageBuffer_SSBO_ISub StorageBuffer + %IMUL = OpSpecConstantOp %uint IMul %UTWO %UTWO + %uint_3 = OpConstant %uint 3 + %37 = OpSpecConstantOp %uint ISub %IMUL %uint_3 +%_arr_float_37 = OpTypeArray %float %37 + %SSBO_IMul = OpTypeStruct %_arr_float_37 %float +%_ptr_StorageBuffer_SSBO_IMul = OpTypePointer StorageBuffer %SSBO_IMul + %IMul = OpVariable %_ptr_StorageBuffer_SSBO_IMul StorageBuffer + %UDIV = OpSpecConstantOp %uint UDiv %UTWO %UTWO +%_arr_float_UDIV = OpTypeArray %float %UDIV + %SSBO_UDiv = OpTypeStruct %_arr_float_UDIV %float +%_ptr_StorageBuffer_SSBO_UDiv = OpTypePointer StorageBuffer %SSBO_UDiv + %UDiv = OpVariable %_ptr_StorageBuffer_SSBO_UDiv StorageBuffer + %SNEG_TWO = OpSpecConstant %int -2 + %SDIV = OpSpecConstantOp %int SDiv %STWO %SNEG_TWO + %int_2 = OpConstant %int 2 + %52 = OpSpecConstantOp %int IAdd %SDIV %int_2 +%_arr_float_52 = OpTypeArray %float %52 + %SSBO_SDiv = OpTypeStruct %_arr_float_52 %float +%_ptr_StorageBuffer_SSBO_SDiv = OpTypePointer StorageBuffer %SSBO_SDiv + %SDiv = OpVariable %_ptr_StorageBuffer_SSBO_SDiv StorageBuffer + %uint_1 = OpConstant %uint 1 +%_arr_float_uint_1 = OpTypeArray %float %uint_1 + %SSBO_SRem = OpTypeStruct %_arr_float_uint_1 %float +%_ptr_StorageBuffer_SSBO_SRem = OpTypePointer StorageBuffer %SSBO_SRem + %SRem = OpVariable %_ptr_StorageBuffer_SSBO_SRem StorageBuffer + %SNEG_THREE = OpSpecConstant %int -3 + %SMOD = OpSpecConstantOp %int SMod %STWO %SNEG_THREE + %66 = OpSpecConstantOp %int IAdd %SMOD %int_2 +%_arr_float_66 = OpTypeArray %float %66 + %SSBO_SMod = OpTypeStruct %_arr_float_66 %float +%_ptr_StorageBuffer_SSBO_SMod = OpTypePointer StorageBuffer %SSBO_SMod + %SMod = OpVariable %_ptr_StorageBuffer_SSBO_SMod StorageBuffer + %UMOD = OpSpecConstantOp %uint UMod %IADD %IMUL + %73 = OpSpecConstantOp %uint ISub %UMOD %uint_1 +%_arr_float_73 = OpTypeArray %float %73 + %SSBO_UMod = OpTypeStruct %_arr_float_73 %float +%_ptr_StorageBuffer_SSBO_UMod = OpTypePointer StorageBuffer %SSBO_UMod + %UMod = OpVariable %_ptr_StorageBuffer_SSBO_UMod StorageBuffer + %LSHL = OpSpecConstantOp %uint ShiftLeftLogical %IADD %ISUB + %uint_11 = OpConstant %uint 11 + %81 = OpSpecConstantOp %uint ISub %LSHL %uint_11 +%_arr_float_81 = OpTypeArray %float %81 + %SSBO_LShl = OpTypeStruct %_arr_float_81 %float +%_ptr_StorageBuffer_SSBO_LShl = OpTypePointer StorageBuffer %SSBO_LShl + %LShl = OpVariable %_ptr_StorageBuffer_SSBO_LShl StorageBuffer + %RSHL = OpSpecConstantOp %uint ShiftRightLogical %IADD %ISUB + %uint_2 = OpConstant %uint 2 + %89 = OpSpecConstantOp %uint ISub %RSHL %uint_2 +%_arr_float_89 = OpTypeArray %float %89 + %SSBO_RShl = OpTypeStruct %_arr_float_89 %float +%_ptr_StorageBuffer_SSBO_RShl = OpTypePointer StorageBuffer %SSBO_RShl + %RShl = OpVariable %_ptr_StorageBuffer_SSBO_RShl StorageBuffer + %95 = OpSpecConstantOp %int IAdd %IADD %uint_0 + %96 = OpSpecConstantOp %int SNegate %95 + %97 = OpSpecConstantOp %int SNegate %SDIV + %RSHA = OpSpecConstantOp %int ShiftRightArithmetic %96 %97 + %int_4 = OpConstant %int 4 + %100 = OpSpecConstantOp %int IAdd %RSHA %int_4 +%_arr_float_100 = OpTypeArray %float %100 + %SSBO_RSha = OpTypeStruct %_arr_float_100 %float +%_ptr_StorageBuffer_SSBO_RSha = OpTypePointer StorageBuffer %SSBO_RSha + %RSha = OpVariable %_ptr_StorageBuffer_SSBO_RSha StorageBuffer + %bool = OpTypeBool + %IEQ = OpSpecConstantOp %bool IEqual %IADD %ISUB + %int_1 = OpConstant %int 1 + %109 = OpSpecConstantOp %int Select %IEQ %int_2 %int_1 +%_arr_float_109 = OpTypeArray %float %109 + %SSBO_IEq = OpTypeStruct %_arr_float_109 %float +%_ptr_StorageBuffer_SSBO_IEq = OpTypePointer StorageBuffer %SSBO_IEq + %IEq = OpVariable %_ptr_StorageBuffer_SSBO_IEq StorageBuffer + %INEQ = OpSpecConstantOp %bool INotEqual %IADD %ISUB + %116 = OpSpecConstantOp %int Select %INEQ %int_1 %int_2 +%_arr_float_116 = OpTypeArray %float %116 + %SSBO_INeq = OpTypeStruct %_arr_float_116 %float +%_ptr_StorageBuffer_SSBO_INeq = OpTypePointer StorageBuffer %SSBO_INeq + %INeq = OpVariable %_ptr_StorageBuffer_SSBO_INeq StorageBuffer + %ULT = OpSpecConstantOp %bool ULessThan %IADD %ISUB + %123 = OpSpecConstantOp %int Select %ULT %int_2 %int_1 +%_arr_float_123 = OpTypeArray %float %123 + %SSBO_Ult = OpTypeStruct %_arr_float_123 %float +%_ptr_StorageBuffer_SSBO_Ult = OpTypePointer StorageBuffer %SSBO_Ult + %Ult = OpVariable %_ptr_StorageBuffer_SSBO_Ult StorageBuffer + %ULE = OpSpecConstantOp %bool ULessThanEqual %IADD %ISUB + %130 = OpSpecConstantOp %int Select %ULE %int_2 %int_1 +%_arr_float_130 = OpTypeArray %float %130 + %SSBO_Ule = OpTypeStruct %_arr_float_130 %float +%_ptr_StorageBuffer_SSBO_Ule = OpTypePointer StorageBuffer %SSBO_Ule + %Ule = OpVariable %_ptr_StorageBuffer_SSBO_Ule StorageBuffer + %UGT = OpSpecConstantOp %bool UGreaterThan %IADD %ISUB + %137 = OpSpecConstantOp %int Select %UGT %int_1 %int_2 +%_arr_float_137 = OpTypeArray %float %137 + %SSBO_Ugt = OpTypeStruct %_arr_float_137 %float +%_ptr_StorageBuffer_SSBO_Ugt = OpTypePointer StorageBuffer %SSBO_Ugt + %Ugt = OpVariable %_ptr_StorageBuffer_SSBO_Ugt StorageBuffer + %UGE = OpSpecConstantOp %bool UGreaterThanEqual %IADD %ISUB + %144 = OpSpecConstantOp %int Select %UGE %int_1 %int_2 +%_arr_float_144 = OpTypeArray %float %144 + %SSBO_Uge = OpTypeStruct %_arr_float_144 %float +%_ptr_StorageBuffer_SSBO_Uge = OpTypePointer StorageBuffer %SSBO_Uge + %Uge = OpVariable %_ptr_StorageBuffer_SSBO_Uge StorageBuffer + %SLT = OpSpecConstantOp %bool SLessThan %SMOD %int_1 + %151 = OpSpecConstantOp %int Select %SLT %int_1 %int_2 +%_arr_float_151 = OpTypeArray %float %151 + %SSBO_Slt = OpTypeStruct %_arr_float_151 %float +%_ptr_StorageBuffer_SSBO_Slt = OpTypePointer StorageBuffer %SSBO_Slt + %Slt = OpVariable %_ptr_StorageBuffer_SSBO_Slt StorageBuffer + %SLE = OpSpecConstantOp %bool SLessThanEqual %SMOD %int_1 + %158 = OpSpecConstantOp %int Select %SLE %int_1 %int_2 +%_arr_float_158 = OpTypeArray %float %158 + %SSBO_Sle = OpTypeStruct %_arr_float_158 %float +%_ptr_StorageBuffer_SSBO_Sle = OpTypePointer StorageBuffer %SSBO_Sle + %Sle = OpVariable %_ptr_StorageBuffer_SSBO_Sle StorageBuffer + %SGT = OpSpecConstantOp %bool SGreaterThan %SMOD %int_1 + %165 = OpSpecConstantOp %int Select %SGT %int_2 %int_1 +%_arr_float_165 = OpTypeArray %float %165 + %SSBO_Sgt = OpTypeStruct %_arr_float_165 %float +%_ptr_StorageBuffer_SSBO_Sgt = OpTypePointer StorageBuffer %SSBO_Sgt + %Sgt = OpVariable %_ptr_StorageBuffer_SSBO_Sgt StorageBuffer + %SGE = OpSpecConstantOp %bool SGreaterThanEqual %SMOD %int_1 + %172 = OpSpecConstantOp %int Select %SGE %int_2 %int_1 +%_arr_float_172 = OpTypeArray %float %172 + %SSBO_Sge = OpTypeStruct %_arr_float_172 %float +%_ptr_StorageBuffer_SSBO_Sge = OpTypePointer StorageBuffer %SSBO_Sge + %Sge = OpVariable %_ptr_StorageBuffer_SSBO_Sge StorageBuffer + %LOR = OpSpecConstantOp %bool LogicalOr %IEQ %SLT + %179 = OpSpecConstantOp %int Select %LOR %int_1 %int_2 +%_arr_float_179 = OpTypeArray %float %179 + %SSBO_Lor = OpTypeStruct %_arr_float_179 %float +%_ptr_StorageBuffer_SSBO_Lor = OpTypePointer StorageBuffer %SSBO_Lor + %Lor = OpVariable %_ptr_StorageBuffer_SSBO_Lor StorageBuffer + %LAND = OpSpecConstantOp %bool LogicalAnd %IEQ %SLT + %186 = OpSpecConstantOp %int Select %LAND %int_2 %int_1 +%_arr_float_186 = OpTypeArray %float %186 + %SSBO_Land = OpTypeStruct %_arr_float_186 %float +%_ptr_StorageBuffer_SSBO_Land = OpTypePointer StorageBuffer %SSBO_Land + %Land = OpVariable %_ptr_StorageBuffer_SSBO_Land StorageBuffer + %LNOT = OpSpecConstantOp %bool LogicalNot %LOR + %193 = OpSpecConstantOp %int Select %LNOT %int_2 %int_1 +%_arr_float_193 = OpTypeArray %float %193 + %SSBO_Lnot = OpTypeStruct %_arr_float_193 %float +%_ptr_StorageBuffer_SSBO_Lnot = OpTypePointer StorageBuffer %SSBO_Lnot + %Lnot = OpVariable %_ptr_StorageBuffer_SSBO_Lnot StorageBuffer + %AND = OpSpecConstantOp %uint BitwiseAnd %IADD %IADD + %200 = OpSpecConstantOp %uint ISub %AND %uint_5 +%_arr_float_200 = OpTypeArray %float %200 + %SSBO_And = OpTypeStruct %_arr_float_200 %float +%_ptr_StorageBuffer_SSBO_And = OpTypePointer StorageBuffer %SSBO_And + %And = OpVariable %_ptr_StorageBuffer_SSBO_And StorageBuffer + %OR = OpSpecConstantOp %uint BitwiseOr %IADD %ISUB + %uint_6 = OpConstant %uint 6 + %208 = OpSpecConstantOp %uint ISub %OR %uint_6 +%_arr_float_208 = OpTypeArray %float %208 + %SSBO_Or = OpTypeStruct %_arr_float_208 %float +%_ptr_StorageBuffer_SSBO_Or = OpTypePointer StorageBuffer %SSBO_Or + %Or = OpVariable %_ptr_StorageBuffer_SSBO_Or StorageBuffer + %XOR = OpSpecConstantOp %uint BitwiseXor %IADD %IADD + %215 = OpSpecConstantOp %uint IAdd %XOR %uint_1 +%_arr_float_215 = OpTypeArray %float %215 + %SSBO_Xor = OpTypeStruct %_arr_float_215 %float +%_ptr_StorageBuffer_SSBO_Xor = OpTypePointer StorageBuffer %SSBO_Xor + %Xor = OpVariable %_ptr_StorageBuffer_SSBO_Xor StorageBuffer + %NOT = OpSpecConstantOp %uint Not %XOR +%uint_4294967294 = OpConstant %uint 4294967294 + %223 = OpSpecConstantOp %uint ISub %NOT %uint_4294967294 +%_arr_float_223 = OpTypeArray %float %223 + %SSBO_Not = OpTypeStruct %_arr_float_223 %float +%_ptr_StorageBuffer_SSBO_Not = OpTypePointer StorageBuffer %SSBO_Not + %Not = OpVariable %_ptr_StorageBuffer_SSBO_Not StorageBuffer + %LEQ = OpSpecConstantOp %bool LogicalEqual %LAND %LNOT + %230 = OpSpecConstantOp %int Select %LEQ %int_1 %int_2 +%_arr_float_230 = OpTypeArray %float %230 + %SSBO_Leq = OpTypeStruct %_arr_float_230 %float +%_ptr_StorageBuffer_SSBO_Leq = OpTypePointer StorageBuffer %SSBO_Leq + %Leq = OpVariable %_ptr_StorageBuffer_SSBO_Leq StorageBuffer + %LNEQ = OpSpecConstantOp %bool LogicalNotEqual %LAND %LNOT + %237 = OpSpecConstantOp %int Select %LNEQ %int_2 %int_1 +%_arr_float_237 = OpTypeArray %float %237 + %SSBO_Lneq = OpTypeStruct %_arr_float_237 %float +%_ptr_StorageBuffer_SSBO_Lneq = OpTypePointer StorageBuffer %SSBO_Lneq + %Lneq = OpVariable %_ptr_StorageBuffer_SSBO_Lneq StorageBuffer + %SEL = OpSpecConstantOp %uint Select %IEQ %IADD %ISUB +%_arr_float_SEL = OpTypeArray %float %SEL + %SSBO_Sel = OpTypeStruct %_arr_float_SEL %float +%_ptr_StorageBuffer_SSBO_Sel = OpTypePointer StorageBuffer %SSBO_Sel + %Sel = OpVariable %_ptr_StorageBuffer_SSBO_Sel StorageBuffer + %249 = OpSpecConstant %uint 1 + %v3uint = OpTypeVector %uint 3 +%gl_WorkGroupSize = OpSpecConstantComposite %v3uint %249 %uint_1 %uint_1 + %TRUE = OpSpecConstantTrue %bool + %FALSE = OpSpecConstantFalse %bool + %main = OpFunction %void None %3 + %5 = OpLabel + %27 = OpAccessChain %_ptr_StorageBuffer_float %IAdd %int_0 %int_0 + OpStore %27 %float_0 + %34 = OpAccessChain %_ptr_StorageBuffer_float %ISub %int_0 %int_0 + OpStore %34 %float_0 + %42 = OpAccessChain %_ptr_StorageBuffer_float %IMul %int_0 %int_0 + OpStore %42 %float_0 + %48 = OpAccessChain %_ptr_StorageBuffer_float %UDiv %int_0 %int_0 + OpStore %48 %float_0 + %57 = OpAccessChain %_ptr_StorageBuffer_float %SDiv %int_0 %int_0 + OpStore %57 %float_0 + %63 = OpAccessChain %_ptr_StorageBuffer_float %SRem %int_0 %int_0 + OpStore %63 %float_0 + %71 = OpAccessChain %_ptr_StorageBuffer_float %SMod %int_0 %int_0 + OpStore %71 %float_0 + %78 = OpAccessChain %_ptr_StorageBuffer_float %UMod %int_0 %int_0 + OpStore %78 %float_0 + %86 = OpAccessChain %_ptr_StorageBuffer_float %LShl %int_0 %int_0 + OpStore %86 %float_0 + %94 = OpAccessChain %_ptr_StorageBuffer_float %RShl %int_0 %int_0 + OpStore %94 %float_0 + %105 = OpAccessChain %_ptr_StorageBuffer_float %RSha %int_0 %int_0 + OpStore %105 %float_0 + %114 = OpAccessChain %_ptr_StorageBuffer_float %IEq %int_0 %int_0 + OpStore %114 %float_0 + %121 = OpAccessChain %_ptr_StorageBuffer_float %INeq %int_0 %int_0 + OpStore %121 %float_0 + %128 = OpAccessChain %_ptr_StorageBuffer_float %Ult %int_0 %int_0 + OpStore %128 %float_0 + %135 = OpAccessChain %_ptr_StorageBuffer_float %Ule %int_0 %int_0 + OpStore %135 %float_0 + %142 = OpAccessChain %_ptr_StorageBuffer_float %Ugt %int_0 %int_0 + OpStore %142 %float_0 + %149 = OpAccessChain %_ptr_StorageBuffer_float %Uge %int_0 %int_0 + OpStore %149 %float_0 + %156 = OpAccessChain %_ptr_StorageBuffer_float %Slt %int_0 %int_0 + OpStore %156 %float_0 + %163 = OpAccessChain %_ptr_StorageBuffer_float %Sle %int_0 %int_0 + OpStore %163 %float_0 + %170 = OpAccessChain %_ptr_StorageBuffer_float %Sgt %int_0 %int_0 + OpStore %170 %float_0 + %177 = OpAccessChain %_ptr_StorageBuffer_float %Sge %int_0 %int_0 + OpStore %177 %float_0 + %184 = OpAccessChain %_ptr_StorageBuffer_float %Lor %int_0 %int_0 + OpStore %184 %float_0 + %191 = OpAccessChain %_ptr_StorageBuffer_float %Land %int_0 %int_0 + OpStore %191 %float_0 + %198 = OpAccessChain %_ptr_StorageBuffer_float %Lnot %int_0 %int_0 + OpStore %198 %float_0 + %205 = OpAccessChain %_ptr_StorageBuffer_float %And %int_0 %int_0 + OpStore %205 %float_0 + %213 = OpAccessChain %_ptr_StorageBuffer_float %Or %int_0 %int_0 + OpStore %213 %float_0 + %220 = OpAccessChain %_ptr_StorageBuffer_float %Xor %int_0 %int_0 + OpStore %220 %float_0 + %228 = OpAccessChain %_ptr_StorageBuffer_float %Not %int_0 %int_0 + OpStore %228 %float_0 + %235 = OpAccessChain %_ptr_StorageBuffer_float %Leq %int_0 %int_0 + OpStore %235 %float_0 + %242 = OpAccessChain %_ptr_StorageBuffer_float %Lneq %int_0 %int_0 + OpStore %242 %float_0 + %248 = OpAccessChain %_ptr_StorageBuffer_float %Sel %int_0 %int_0 + OpStore %248 %float_0 + OpReturn + OpFunctionEnd diff --git a/tests/test-spirv-reflect.cpp b/tests/test-spirv-reflect.cpp index 93456e75..19a83768 100644 --- a/tests/test-spirv-reflect.cpp +++ b/tests/test-spirv-reflect.cpp @@ -830,6 +830,7 @@ TEST(SpirvReflectTestCase, TestComputeLocalSize) { ASSERT_EQ(module_.entry_points[0].local_size.x, 1); ASSERT_EQ(module_.entry_points[0].local_size.y, 1); ASSERT_EQ(module_.entry_points[0].local_size.z, 1); + ASSERT_EQ(module_.entry_points[0].local_size.flags, 0); spvReflectDestroyShaderModule(&module_); } @@ -1229,3 +1230,28 @@ TEST_F(SpirvReflectMultiEntryPointTest, ChangeDescriptorSetNumber) { ASSERT_EQ(set0->bindings[0], set1->bindings[1]); ASSERT_EQ(set0->bindings[0]->set, 1); } + +TEST(SpirvReflectSpecializationConstantTest, TestSpecParsing) { + std::vector spirv_; + SpvReflectShaderModule module_; + const std::string spirv_path = "../tests/entry_exec_mode/comp_local_size.spv"; + std::ifstream spirv_file(spirv_path, std::ios::binary | std::ios::ate); + std::streampos spirv_file_nbytes = spirv_file.tellg(); + spirv_file.seekg(0); + spirv_.resize(spirv_file_nbytes); + spirv_file.read(reinterpret_cast(spirv_.data()), spirv_.size()); + + SpvReflectResult result = + spvReflectCreateShaderModule(spirv_.size(), spirv_.data(), &module_); + ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result) + << "spvReflectCreateShaderModule() failed"; + + EXPECT_EQ(module_.entry_point_count, 1); + EXPECT_EQ(module_.entry_points[0].shader_stage, SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT); + EXPECT_EQ(module_.entry_points[0].local_size.x, 1); + EXPECT_EQ(module_.entry_points[0].local_size.y, 1); + EXPECT_EQ(module_.entry_points[0].local_size.z, 1); + EXPECT_EQ(module_.entry_points[0].local_size.flags, 4); + + spvReflectDestroyShaderModule(&module_); +} From a9025fc096e776ffec26f2a9878d95a172d76f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sun, 7 Aug 2022 18:54:07 +0800 Subject: [PATCH 26/44] Add tests All tests passing --- spirv_reflect.c | 60 +-- tests/spec_constant/test_32bit.spv | Bin 11500 -> 11832 bytes tests/spec_constant/test_32bit.spv.dis | 434 ++++++++--------- tests/spec_constant/test_32bit.spv.dis.patch | 10 +- tests/spec_constant/test_64bit.spv | Bin 11616 -> 11944 bytes tests/spec_constant/test_64bit.spv.dis | 438 +++++++++--------- tests/spec_constant/test_64bit.spv.dis.patch | 26 +- tests/spec_constant/test_convert.glsl | 15 +- tests/spec_constant/test_convert.spv | Bin 2064 -> 2112 bytes tests/spec_constant/test_convert.spv.dis | 41 +- .../spec_constant/test_convert.spv.dis.patch | 44 +- tests/spec_constant/test_localsizeid.spv | Bin 11444 -> 11776 bytes tests/spec_constant/test_localsizeid.spv.dis | 434 ++++++++--------- .../test_localsizeid.spv.dis.patch | 16 +- tests/spec_constant/test_orig.glsl | 47 +- tests/spec_constant/test_orig.spv.dis | 434 ++++++++--------- tests/test-spirv-reflect.cpp | 411 +++++++++++++++- 17 files changed, 1428 insertions(+), 982 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index 77183647..f8060f7e 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -27,6 +27,8 @@ #include #endif +#include + #if defined(SPIRV_REFLECT_ENABLE_ASSERTS) #define SPV_REFLECT_ASSERT(COND) \ assert(COND); @@ -3626,9 +3628,11 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars default: continue; case SpvOpSpecConstantTrue: { p_module->specialization_constants[index].default_value.value.uint32_bool_value = 1; + p_module->specialization_constants[index].type = FindType(p_module, p_node->result_type_id); } break; case SpvOpSpecConstantFalse: { p_module->specialization_constants[index].default_value.value.uint32_bool_value = 0; + p_module->specialization_constants[index].type = FindType(p_module, p_node->result_type_id); } break; case SpvOpSpecConstant: { SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS; @@ -5907,12 +5911,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect } \ } -#define SHIFT_OP_32_BIT_HOOK_PRE -#define SHIFT_OP_64_BIT_HOOK_PRE -#define SHIFT_OP_32_BIT_HOOK_POST -#define SHIFT_OP_64_BIT_HOOK_POST - -#define DO_SHIFT_OPERATION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP) \ +#define DO_SHIFT_OPERATION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, _32bit_type, _64bit_type, _32bit_member, _64bit_member, res, CLEANUP)\ { \ switch (mode) { \ default: \ @@ -5965,20 +5964,16 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect goto CLEANUP; \ case 32: \ { \ - uint32_t data = operand1->value.data.numeric.vector.value[i].value.uint32_bool_value; \ - SHIFT_OP_32_BIT_HOOK_PRE \ + _32bit_type data = operand1->value.data.numeric.vector.value[i].value.##_32bit_member; \ data operation##= shift_num; \ - SHIFT_OP_32_BIT_HOOK_POST \ - (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value = data; \ + (simple_op_node)->value.data.numeric.vector.value[i].value.##_32bit_member = data; \ } \ break; \ case 64: \ { \ - uint64_t data = operand1->value.data.numeric.vector.value[i].value.uint64_value; \ - SHIFT_OP_64_BIT_HOOK_PRE \ + _64bit_type data = operand1->value.data.numeric.vector.value[i].value.##_64bit_member; \ data operation##= shift_num; \ - SHIFT_OP_64_BIT_HOOK_POST \ - (simple_op_node)->value.data.numeric.vector.value[i].value.uint64_value = data; \ + (simple_op_node)->value.data.numeric.vector.value[i].value.##_64bit_member = data; \ } \ break; \ } \ @@ -6015,6 +6010,11 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect } \ } +#define DO_ARITHMETIC_SHIFT_OPERATION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP)\ + DO_SHIFT_OPERATION(mode, p_simple_op_parser, simple_op_eval, simple_op_node, operation, int32_t, int64_t, sint32_value, sint64_value, res, CLEANUP) +#define DO_LOGICAL_SHIFT_OPERATION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP)\ + DO_SHIFT_OPERATION(mode, p_simple_op_parser, simple_op_eval, simple_op_node, operation, uint32_t, uint64_t, uint32_bool_value, uint64_value, res, CLEANUP) + #define DO_BINARY_BOOLEAN_LOGICAL_OPERATION(mode, p_simple_op_parser,simple_op_eval, simple_op_node, operation, res, CLEANUP) \ { \ switch (mode) { \ @@ -6300,7 +6300,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect { for (uint32_t i = 0; i < p_node->num_id_operands; ++i) { GET_OPERAND(p_parser, p_eval, p_node, 3 + i, p_node->id_operands[i], res, CLEANUP) - // check type compatibility + // check type compatibility if (p_node->id_operands[i]->value.type->id != p_node->value.type->component_type_id) { res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; @@ -6756,39 +6756,15 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect break; case SpvOpShiftRightLogical: // zero fill right shift. Just >> in c - DO_SHIFT_OPERATION(evaluation_mode, p_parser, p_eval, p_node, >> , res, CLEANUP) + DO_LOGICAL_SHIFT_OPERATION(evaluation_mode, p_parser, p_eval, p_node, >> , res, CLEANUP) break; case SpvOpShiftRightArithmetic: // fill with sign of original number. - #undef SHIFT_OP_32_BIT_HOOK_PRE - #undef SHIFT_OP_64_BIT_HOOK_PRE - #undef SHIFT_OP_32_BIT_HOOK_POST - #undef SHIFT_OP_64_BIT_HOOK_POST - #define SHIFT_OP_32_BIT_HOOK_PRE uint32_t sign_bit = data & 0x80000000; - #define SHIFT_OP_64_BIT_HOOK_PRE uint64_t sign_bit = data & 0x8000000000000000; - #define SHIFT_OP_32_BIT_HOOK_POST \ - if (sign_bit) { \ - uint32_t fill = 0xffffffff << (32 - shift_num); \ - data |= fill; \ - } - #define SHIFT_OP_64_BIT_HOOK_POST \ - if (sign_bit) { \ - uint64_t fill = 0xffffffffffffffff << (64 - shift_num); \ - data |= fill; \ - } - DO_SHIFT_OPERATION(evaluation_mode, p_parser, p_eval, p_node, >> , res, CLEANUP) - #undef SHIFT_OP_32_BIT_HOOK_PRE - #undef SHIFT_OP_64_BIT_HOOK_PRE - #undef SHIFT_OP_32_BIT_HOOK_POST - #undef SHIFT_OP_64_BIT_HOOK_POST - #define SHIFT_OP_32_BIT_HOOK_PRE - #define SHIFT_OP_64_BIT_HOOK_PRE - #define SHIFT_OP_32_BIT_HOOK_POST - #define SHIFT_OP_64_BIT_HOOK_POST + DO_ARITHMETIC_SHIFT_OPERATION(evaluation_mode, p_parser, p_eval, p_node, >> , res, CLEANUP) break; case SpvOpShiftLeftLogical: // zero fill left shift. Just << in c - DO_SHIFT_OPERATION(evaluation_mode, p_parser, p_eval, p_node, << , res, CLEANUP) + DO_LOGICAL_SHIFT_OPERATION(evaluation_mode, p_parser, p_eval, p_node, << , res, CLEANUP) break; case SpvOpBitwiseOr: DO_SIMPLE_BINARY_INTEGER_OPERATION(evaluation_mode, p_parser, p_eval, p_node, | , res, CLEANUP) diff --git a/tests/spec_constant/test_32bit.spv b/tests/spec_constant/test_32bit.spv index b1b58fb83f4fd37e1ff0e42fb9149378e18f943b..7a8f6023c6dd192ac778ed6c0a0dfee0a5d84373 100644 GIT binary patch literal 11832 zcmZvi2bi5z5r(hX-Bd^jNeG>UDuPG}MUk?QWwUa#D|>SVL|kIBglGySL9xK9h=K@; zB4Y2@d+%cJz4zXGFNp7Z?mx-oJUKkW%=eu+^UXPbx&QLeH|?Mqt$};ATCEwaIXcGt z*0h%4oYwT>hufX@QCDnPd(^Vyk9K};t4~+v=CuxP4G>SmHm+X3N#5ChOny2x1DlD> z!e(Q0uwAfSvANhhY&UE^wmY@}TZk>f_P`cndt!TGdt>`x`(pcH`(p=SOR%NbZYbJ| zwe-?Tvr)YJyK8#o`IY(%TYb~$!NN-8eK0>^*+s2i;N8)>RS8m-vY+X4=)D_oty?;h} zOG@2)gS*Q|9)v4(kHVL_-R0}AB(|=cBkGFly55t`l2YeB;NID+7$4%wd4AsLouqY) z*t6+u*OGIDmbljP-fxzay2pyghgRZ>_Hp7;cYJaqv3rnnL|t)R*XOCzTT<#S6R#ZG zcHbN?E_GLKj{8Q=5p~6NU7yiTZ%L_p0=S#%p6I-FyW8u^Iijw(uIqE(EGczQ0=GLW z+PHEK_r;gG?an1}kH|TquDGu2yQEoC>fR4Lp6Z?qE_KJZ*OhZbU2$D^7r16gseAu| zR}A7xzo+1%?rLJMo17!+itD<*^Qh|*>h!fv#g7b~Q)-?@TxyOCUFN(sv^Mg+e4+EFUzLhBw?v1=ZJdZy54-a?uN-y?=0itUVp>H zy?X1m^(W_udg8jCzdc=+*xw4{;a-0u#7(_z{mD6^p17{(?^t(TufGQncbfA%+qgWN z+s{wV5%t7%J%1BB&H4G@bei+?Wzy8!)?azSz(+lCUC-awPIG>v#?ATpW7Vs-{rt)g z7<|+d*Y*6Z?lkB3K;!28ycwH%+xjavD16it*Y*6}?=lU2rpqubt>U2w1F>P_*!lygK)@s2h7%Qs28x1`kd$EiI!X8F?V zx%gh)O`E+Leg5PeQCD2o^*g8CTSA?_)_Gvt9pInyiA&AF(rT$G=ZKo(9c%WL?u_J1U>so$)kzQ&&g!sJX+FVFnYMrPgp17{JADm0< z?V-dTp?jSmF7-ys@sItY2jX2nt-%L1xUaznH+Z1IhcwvlC)Zzs zH}1z)pl}%8VI4Xhc(4Z3+iFNTV3B<+uvGGoHgV7G;78;YSxqs zO>1RMv6|}G!^81e<4CY0Ysi_OHRM9WGs_xcHDdk|#91T0TeC)dyJii!sNwpoAy%Ug zb02=!+T)A{dn0AdW5ABADOc}HE;Ox`HN|Si_1Q?AHI4&2vW8r(Ar~5c+hz^18gU

&O~%wT4`1%puMiVl_N7_i-6MYxu3}$Qp9BhFoauLYy_kYItU9_#>P(P60czhFq;7 z7aF?~XAQ9$o|zg~;IqbQU`N)Ft2N|8V=i&l5Ub&tsnPp=-u^xtgm+{OxmrUmH0BX! z4e?UUGgD(LKJVj9up?{8)f#f4;eRX18e%m(Gc|gD3vb`Y5WFL6$kiHhp)sF0YlzkG z%+z=!KJQ}~?8q8&wT4`1>`t6D#ALz><1zTGF$Q*I4Y^uF zE;Rgp&l+MiJTo;Oi_aS8fE`&wuGWwXjm5-SL#&2prpDv&S)&7XWDU7mLoPJ@&d(ZR zH9RvluEuALF4&PZziXQsxJ z@ve{Wl&28;I~@1K#mzjf)eE2f;o<8@Xb9~);a%lYzlL|bLz<-jHzdR@iVX~%zWn}?-1hX z!@NVWDa?H5LiZNp0W9i0llTdk`OfW&?j?B7!MXjxhv9=;0)7_QZxQ*E8{F4$>Ua*f zVh*vjo?VdV(BHa^*!A*puJE_@Y`^ZwoY>dx#P$$*&m}g` zeCOQPdc2y>xvzWSgR`&af$dA)eTn-UF6tfuz7|to3;y}U>Ny{J4<}a7IrWaj2dCZ( z!0O4XC-&ONMcsQ7Ux$UB`*;M{y3SemD130%eIeKy^41kkZ@4(``+)Ci&ih8d!%zlo+2WLMo0q=sz+mCog!?{oE9*f<8g?{ia zh4WmU550}V>N%(0arofWdl^_gdG*9I8!qZD16w2XV!tnkn}$W+D~P8GZnd0qznk!` zbx!@`@xiJ8O0fF!>WgPJoON#^J^{NPI}|&jSnqkigE-FHyjNlF-+brP-;7t^IrUG( z2dDn4!RpJaFP`0Sq5m4Nbq~k9UxPo1_@kJ8nG?^~Yl-Jzk@q@c*PHL0eO-#TFX!y* zzWCtm>-Av!lD99hHRYo28;Ez-*Ztt{#O%wQ=>k$v3L%zAhsvx?dddpaQ5_GuszA!lXz~!MNjVo=boaM)8Su> z*^4>R%lnD#<#fzG?8o!jg0~mv?PU-joV|PiY%lWmBA(Z9(aQ(HJL}~Pc<&v1F(-QY z5V5^DpU-70*j_$_*~^*u;OynYV0)3b7x8Wl7ropG-dQip;l0=F#hmEH`^sLN&%Im; zwioB^We6Xfy?hjGFY@*xp5JiM%g4Yw>*Xx?*J1WzPW19|Vta8uU!zBY?ZtU}8O8@^ zFP{M0i@d#vcW=1p<&)r@^|Auq_kz8c6TN(j*j}8^y*vtRFV5S`2tGJ_`83#G3r6_3aqB{YMzY`PR-AP)s$CLys+UyvkmtBQEPq< zPEF^t=A*%CIdC7o-n-%4<4wfp zVLr<~n_BSSBKBE!{ua#l_!M3}=hQnNKZVJu_iem-^6H8AX}GBS9dP}Qu#X30zNhTL zocMdC7o-Vc-WI=kP8V!jKl8+-i`asE5&$6)K4>zvw8#H;O` z+7tNT)cy%r9eK6I`!}3>dN=V!nD>$QulH2kXFnzOKD!8e5oV5>*W%T5Ud`3`;MDvX zSWS5~#RoK8Xg&=53ar-rIh>l#tEaA-Pr|F|yqat9!KwKRu$uB}ikD!$Gw$8nzXW@J zhhw*6?$fhhi>Y}k=Cw9Y&Fk=LIeo=r{O5YTbtaEoSXo8#@&w_iQY3 zen)ISIY%z%{2n||<;dlnKY*uKIdVDYkKh?qj$F?96L@BoBbRgj44zfx$mN{BfM-`Z zayjR(;5k)}T+aC$*lU{4M=t059lUFmBbRgj0iIjs$mN`Wg6CB^ayjQ;;N7Ymxt#NF z@cb%AF6aCQynB@+mvjCLUQp%8<(#{~3#%Ntobx~MqAEu&=iCk6qso!XIsS3IxXO{s zIrjkXS>?#(oN3^_svNnT(+A$W%8|=C{osA79J!q1|609ol_QsPrh|R|=X*>p=ga{6 mp3XUPIcFx=_iE0O%Q>^aOR5~XoHHA|w91h)=PnNXB<%nBJSVjP literal 11500 zcmZ9Q2b^5hb%!TgB!N%^A({{Z(@Za-H!aq(S{UuZjs`?AE1_LLW+hQ1+1QjdrkG&d zVmmG=N{n0VBzBx`CvgaInw{8*yVI*nda+3X@_l#SSsmT``yI~t|L=Y0yYJ4M*(dt@ zUN*lq_yet0YkuoR{_9xQ>TBsNY|Sfqq}^$sao?_~GuE7Umh+2S{iZUvq;-62kh+i9 zzGd4EeP;&<{dvTEVgYdgaUijfIEYw8EGCu^ONnK~!NeiNa^g^81#uX0IB^7VBykk6 zk~o@JMI1w{CXOYRLUb?oGRI!}snpMMV*~7Bq&+z@K0eYOp4@u(-IMq2x_@SRa%S6( z>B*^W_fBu!wQbL|>lUPS+jeZ7**%pP46-8MxB563o$;|@68AsQdYO9T4dbDYr|72n z6Vz$`MD*y;x^=zvgRPS&I-M)WCr5{-rl{x9Q_rzy%M7}=#?NbN_xA1gljVBf%_T*j ztnPHLB%udeFDLi3bTwyKeM)Qt5j-x%BO>+qQ?=zIu-6tFHU{{56-9K4+jiW5Xkp>CDg6 zODrGq!s_f}l?NX`Sn8VPbKYE1SZB}mnV8;A?Vj}<(MMhP@w?LLT~hj-qb_@1KQYXc z<>z~@-iGnH=VXoA=cKb?XFMl*j$o;4mfy+dlG67)bT{=q-+B9X_x06tL|=8?*YA0A zN$Gn5y4_hn_ncgaE`8gbJL5Ugb3|Wt-Phla=91F)BJ@P+dojB7o!Hk`&k=pqb>D;V znoCOGONw4UL_!a?E+t3bE!2LNdXDI;uKO;+qpz3HrN4Ck_+~-S8k4EX)o!LcMdg?i%r+WXM{pB~^OYHXw=DY3T($9ys={HST`jrQnI{K;We#`K> zGt;FXUxQY6q_@ATsC)hHnA@M8Bl@Z9e*UfLa*6vJu^#E|Z#{L>Z*G5jj_9YZ`}udP zdq;17qtu<|{I0ex-_3pJr{{=%>bl=@yiRj|*H|~_=a;DIH@Cm?#lnw%>bjqQPdm-| zZLn_6Z_K*vZ{PXpIijDs?zaN3)104w;5yCuU2EOzH@81MNAy$I{ro%MY0l3Fx;;Ko zo|g%I`?Yu8OIe;5JxBCY*Zq8F@Djf#9qXa7@|X?cY()2ZZrL$K?e|2_5k1xW_Z%qi zAno2IrEixt?XmH4seP|U_xkSGxr^GqdXDI;uKW64)9zhDm;TlbXt!(6P1L35P}yqf zspp8E>iv86m-i$uvEPl%bDY!zt(&MzzwvuZFSR3jsq0?8Z?U}ex|w=Y^V!@&U3zWW z_u1$CE z`3#nxo#`3MvQIrn^i=QPv%kFadWrk=%eHZ%JM1;;+sRiAwL2Ok=;O#<-`8m0P1U|D zI)8kl2OE7tqvtjH4zl$Cu^vLahuX&xo;~$kH$r#U1yh#$aL802TU1ZqNu3$-PMR6< zUYZ$t!H}C7Y8mcJ<~DL>#QSMx#5-zc=moXNFov z+{aGpd>;ES%uvhl%w#-F&WufH zM`q~N4836Z|4uVQEyFXDF-y*jo6wHT(5o4G!B|P18S2bz1~@r z=P=NE7q!>x$3A|TdY16qy#Me|rgnecgKOO1on)_d&i%cd9G?B(jkdqO`%@1zUi3W$ z{U~AId_M0%doQu>z0~qu@0|Q?Wckj?Kb0Jw{P&^d>&sVr=6cchG-{vU;M@0AX!|;6 z-_yzA+4o1#_RzPldS2tj^LYmP#g|@sNsgbxnZy%>&!Thj`TQt#9}(+*jCz)Ey>ss8 zF0%V^&i$N44$uAkINJT_yC3!Z#*61|FWTqVelukI?IrAYHaR@|{RG;6`u0;VXuP<; zbI>oO`#TryeR_Y+#r^yw^(^6h+|PDu`Oe8-Lk>^=`_c0C<*N^v^LpRE^UzNceqT-@ z;`4ll+ULaiy@dC>gDlTEdFPYEllK9%JbiiU0~;^;UVwg%kmvIr=lVhFg+#3T5Vd^Q zJ12i9S-x}fFC>R2|HEkc`tsHG?43dHelJ2lOVs?2;Pnx~|0!zuu6IuU-DLUB$-kH! zp8SuZW$DWg9sH;8KSsYB-{&s0Oy^}@Ne)luub}O(FH^m= z@q+mZv}ay3e-%%r^O?CDEz^0K>&W5B{1jTIzD)J9#tY^!`eQ`R{4}0S=kwX_LCbVr z=2hhIWd0gjroK$|!HpNp5wy>A&HQydna*eCtI;x@m${xCp3L7s%hZ>tKBV!2Ig0i< zKbNp~JVT$Mmg#(Ez6LGxGla~m$>GWTO|(pXnd;?@7tCwW_NnD8KU2Re_mgEh zFSAV!Po}>IGWBJu4{f|)Zb18+Q8S;zlj(eZhF*)7>AcJ_a(FU-8!b~`rg}x=1#=wj zZ%@tqES^l~GxK$5na<0+mK>hU-$BdNm#IFi@q&3B`h&z}gr8k}p1(^i(|ON6&h`On zna<0cAcrUO_s}x+WvUNvykK_FA0lez@8ijIKHukqXqnE-+(-^j<{zMC>dRCg(RluC z@VB5#e3LVM^dwiPu2Ey|`v5D~i5d8?@ z{M!hh*N4gSoRhbS9G<*CLd(;ar#`CjqVJ7ppDB4K6Y-w#1?qW3totIheAhcCf0iuY zIr%q{X9+#|e@vFIFJHZ~@uKg|=+6@M{r(BwEaCiKLf-4i_I6I*E#&azeF-g3U!MBt z#`E*^d|yfU4B9vD^~==p?(3Sb5ZGWVDq6O_Z1t+f^Imaa!hoZZy7Q=iZC@J4bU;dqjG9`)zs zA$q-w{1=41-_gY7D7|+QvF0zS-A`Vlm)HCidazofm)HC?dS10gFR%F<^!#d#US9LJ z=mpgpy}ah{&<9j&^zxd&M;}`8Ik{wMH+m`3`z< zwMH+m`7U}%wMH+m`A789YK>lA^H1ny)f&CL=AY3AS8Me0ntwqbQmxU;YyK6zyjr7| z*Zdp$&}xldUi0th71bKOyyid9hgECz@|yodA6~7|%WM7%eMGfJFR%F?`p9aHUS9Kk z^ikCsy}agm^vY_DUS9Lx=%cGOdU?(Np#440&!Jvk^S@|+Kl2*ByypMVtE)A7dCd!G Rf46cUJ=eUzzuGP&{vV3Y3W)#! diff --git a/tests/spec_constant/test_32bit.spv.dis b/tests/spec_constant/test_32bit.spv.dis index 79611c17..a20ac030 100644 --- a/tests/spec_constant/test_32bit.spv.dis +++ b/tests/spec_constant/test_32bit.spv.dis @@ -1,7 +1,7 @@ ; SPIR-V ; Version: 1.5 ; Generator: Google Shaderc over Glslang; 10 -; Bound: 254 +; Bound: 267 ; Schema: 0 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -22,6 +22,7 @@ OpMemberName %SSBO_IAdd 0 "val" OpMemberName %SSBO_IAdd 1 "dummy" OpName %IAdd "IAdd" + OpName %SNEG_TWO "SNEG_TWO" OpName %ISUB "ISUB" OpName %SSBO_ISub "SSBO_ISub" OpMemberName %SSBO_ISub 0 "val" @@ -37,17 +38,17 @@ OpMemberName %SSBO_UDiv 0 "val" OpMemberName %SSBO_UDiv 1 "dummy" OpName %UDiv "UDiv" - OpName %SNEG_TWO "SNEG_TWO" + OpName %SNEG_THREE "SNEG_THREE" OpName %SDIV "SDIV" OpName %SSBO_SDiv "SSBO_SDiv" OpMemberName %SSBO_SDiv 0 "val" OpMemberName %SSBO_SDiv 1 "dummy" OpName %SDiv "SDiv" + OpName %SREM "SREM" OpName %SSBO_SRem "SSBO_SRem" OpMemberName %SSBO_SRem 0 "val" OpMemberName %SSBO_SRem 1 "dummy" OpName %SRem "SRem" - OpName %SNEG_THREE "SNEG_THREE" OpName %SMOD "SMOD" OpName %SSBO_SMod "SSBO_SMod" OpMemberName %SSBO_SMod 0 "val" @@ -185,13 +186,14 @@ OpDecorate %SSBO_IAdd Block OpDecorate %IAdd DescriptorSet 0 OpDecorate %IAdd Binding 0 - OpDecorate %_arr_float_ISUB ArrayStride 4 + OpDecorate %SNEG_TWO SpecId 4 + OpDecorate %_arr_float_32 ArrayStride 4 OpMemberDecorate %SSBO_ISub 0 Offset 0 OpMemberDecorate %SSBO_ISub 1 Offset 4 OpDecorate %SSBO_ISub Block OpDecorate %ISub DescriptorSet 0 OpDecorate %ISub Binding 1 - OpDecorate %_arr_float_37 ArrayStride 4 + OpDecorate %_arr_float_39 ArrayStride 4 OpMemberDecorate %SSBO_IMul 0 Offset 0 OpMemberDecorate %SSBO_IMul 1 Offset 4 OpDecorate %SSBO_IMul Block @@ -203,171 +205,170 @@ OpDecorate %SSBO_UDiv Block OpDecorate %UDiv DescriptorSet 0 OpDecorate %UDiv Binding 3 - OpDecorate %SNEG_TWO SpecId 4 - OpDecorate %_arr_float_52 ArrayStride 4 + OpDecorate %SNEG_THREE SpecId 7 + OpDecorate %_arr_float_54 ArrayStride 4 OpMemberDecorate %SSBO_SDiv 0 Offset 0 OpMemberDecorate %SSBO_SDiv 1 Offset 4 OpDecorate %SSBO_SDiv Block OpDecorate %SDiv DescriptorSet 0 OpDecorate %SDiv Binding 4 - OpDecorate %_arr_float_uint_1 ArrayStride 4 + OpDecorate %_arr_float_61 ArrayStride 4 OpMemberDecorate %SSBO_SRem 0 Offset 0 OpMemberDecorate %SSBO_SRem 1 Offset 4 OpDecorate %SSBO_SRem Block OpDecorate %SRem DescriptorSet 0 OpDecorate %SRem Binding 5 - OpDecorate %SNEG_THREE SpecId 7 - OpDecorate %_arr_float_66 ArrayStride 4 + OpDecorate %_arr_float_69 ArrayStride 4 OpMemberDecorate %SSBO_SMod 0 Offset 0 OpMemberDecorate %SSBO_SMod 1 Offset 4 OpDecorate %SSBO_SMod Block OpDecorate %SMod DescriptorSet 0 OpDecorate %SMod Binding 6 - OpDecorate %_arr_float_73 ArrayStride 4 + OpDecorate %_arr_float_77 ArrayStride 4 OpMemberDecorate %SSBO_UMod 0 Offset 0 OpMemberDecorate %SSBO_UMod 1 Offset 4 OpDecorate %SSBO_UMod Block OpDecorate %UMod DescriptorSet 0 OpDecorate %UMod Binding 7 - OpDecorate %_arr_float_81 ArrayStride 4 + OpDecorate %_arr_float_86 ArrayStride 4 OpMemberDecorate %SSBO_LShl 0 Offset 0 OpMemberDecorate %SSBO_LShl 1 Offset 4 OpDecorate %SSBO_LShl Block OpDecorate %LShl DescriptorSet 0 OpDecorate %LShl Binding 8 - OpDecorate %_arr_float_89 ArrayStride 4 + OpDecorate %_arr_float_95 ArrayStride 4 OpMemberDecorate %SSBO_RShl 0 Offset 0 OpMemberDecorate %SSBO_RShl 1 Offset 4 OpDecorate %SSBO_RShl Block OpDecorate %RShl DescriptorSet 0 OpDecorate %RShl Binding 9 - OpDecorate %_arr_float_100 ArrayStride 4 + OpDecorate %_arr_float_106 ArrayStride 4 OpMemberDecorate %SSBO_RSha 0 Offset 0 OpMemberDecorate %SSBO_RSha 1 Offset 4 OpDecorate %SSBO_RSha Block OpDecorate %RSha DescriptorSet 0 OpDecorate %RSha Binding 10 - OpDecorate %_arr_float_109 ArrayStride 4 + OpDecorate %_arr_float_115 ArrayStride 4 OpMemberDecorate %SSBO_IEq 0 Offset 0 OpMemberDecorate %SSBO_IEq 1 Offset 4 OpDecorate %SSBO_IEq Block OpDecorate %IEq DescriptorSet 0 OpDecorate %IEq Binding 11 - OpDecorate %_arr_float_116 ArrayStride 4 + OpDecorate %_arr_float_123 ArrayStride 4 OpMemberDecorate %SSBO_INeq 0 Offset 0 OpMemberDecorate %SSBO_INeq 1 Offset 4 OpDecorate %SSBO_INeq Block OpDecorate %INeq DescriptorSet 0 OpDecorate %INeq Binding 12 - OpDecorate %_arr_float_123 ArrayStride 4 + OpDecorate %_arr_float_131 ArrayStride 4 OpMemberDecorate %SSBO_Ult 0 Offset 0 OpMemberDecorate %SSBO_Ult 1 Offset 4 OpDecorate %SSBO_Ult Block OpDecorate %Ult DescriptorSet 0 OpDecorate %Ult Binding 13 - OpDecorate %_arr_float_130 ArrayStride 4 + OpDecorate %_arr_float_139 ArrayStride 4 OpMemberDecorate %SSBO_Ule 0 Offset 0 OpMemberDecorate %SSBO_Ule 1 Offset 4 OpDecorate %SSBO_Ule Block OpDecorate %Ule DescriptorSet 0 OpDecorate %Ule Binding 14 - OpDecorate %_arr_float_137 ArrayStride 4 + OpDecorate %_arr_float_147 ArrayStride 4 OpMemberDecorate %SSBO_Ugt 0 Offset 0 OpMemberDecorate %SSBO_Ugt 1 Offset 4 OpDecorate %SSBO_Ugt Block OpDecorate %Ugt DescriptorSet 0 OpDecorate %Ugt Binding 15 - OpDecorate %_arr_float_144 ArrayStride 4 + OpDecorate %_arr_float_155 ArrayStride 4 OpMemberDecorate %SSBO_Uge 0 Offset 0 OpMemberDecorate %SSBO_Uge 1 Offset 4 OpDecorate %SSBO_Uge Block OpDecorate %Uge DescriptorSet 0 OpDecorate %Uge Binding 16 - OpDecorate %_arr_float_151 ArrayStride 4 + OpDecorate %_arr_float_162 ArrayStride 4 OpMemberDecorate %SSBO_Slt 0 Offset 0 OpMemberDecorate %SSBO_Slt 1 Offset 4 OpDecorate %SSBO_Slt Block OpDecorate %Slt DescriptorSet 0 OpDecorate %Slt Binding 17 - OpDecorate %_arr_float_158 ArrayStride 4 + OpDecorate %_arr_float_169 ArrayStride 4 OpMemberDecorate %SSBO_Sle 0 Offset 0 OpMemberDecorate %SSBO_Sle 1 Offset 4 OpDecorate %SSBO_Sle Block OpDecorate %Sle DescriptorSet 0 OpDecorate %Sle Binding 18 - OpDecorate %_arr_float_165 ArrayStride 4 + OpDecorate %_arr_float_176 ArrayStride 4 OpMemberDecorate %SSBO_Sgt 0 Offset 0 OpMemberDecorate %SSBO_Sgt 1 Offset 4 OpDecorate %SSBO_Sgt Block OpDecorate %Sgt DescriptorSet 0 OpDecorate %Sgt Binding 19 - OpDecorate %_arr_float_172 ArrayStride 4 + OpDecorate %_arr_float_183 ArrayStride 4 OpMemberDecorate %SSBO_Sge 0 Offset 0 OpMemberDecorate %SSBO_Sge 1 Offset 4 OpDecorate %SSBO_Sge Block OpDecorate %Sge DescriptorSet 0 OpDecorate %Sge Binding 20 - OpDecorate %_arr_float_179 ArrayStride 4 + OpDecorate %_arr_float_190 ArrayStride 4 OpMemberDecorate %SSBO_Lor 0 Offset 0 OpMemberDecorate %SSBO_Lor 1 Offset 4 OpDecorate %SSBO_Lor Block OpDecorate %Lor DescriptorSet 0 OpDecorate %Lor Binding 21 - OpDecorate %_arr_float_186 ArrayStride 4 + OpDecorate %_arr_float_197 ArrayStride 4 OpMemberDecorate %SSBO_Land 0 Offset 0 OpMemberDecorate %SSBO_Land 1 Offset 4 OpDecorate %SSBO_Land Block OpDecorate %Land DescriptorSet 0 OpDecorate %Land Binding 22 - OpDecorate %_arr_float_193 ArrayStride 4 + OpDecorate %_arr_float_204 ArrayStride 4 OpMemberDecorate %SSBO_Lnot 0 Offset 0 OpMemberDecorate %SSBO_Lnot 1 Offset 4 OpDecorate %SSBO_Lnot Block OpDecorate %Lnot DescriptorSet 0 OpDecorate %Lnot Binding 23 - OpDecorate %_arr_float_200 ArrayStride 4 + OpDecorate %_arr_float_211 ArrayStride 4 OpMemberDecorate %SSBO_And 0 Offset 0 OpMemberDecorate %SSBO_And 1 Offset 4 OpDecorate %SSBO_And Block OpDecorate %And DescriptorSet 0 OpDecorate %And Binding 24 - OpDecorate %_arr_float_208 ArrayStride 4 + OpDecorate %_arr_float_220 ArrayStride 4 OpMemberDecorate %SSBO_Or 0 Offset 0 OpMemberDecorate %SSBO_Or 1 Offset 4 OpDecorate %SSBO_Or Block OpDecorate %Or DescriptorSet 0 - OpDecorate %Or Binding 24 - OpDecorate %_arr_float_215 ArrayStride 4 + OpDecorate %Or Binding 25 + OpDecorate %_arr_float_227 ArrayStride 4 OpMemberDecorate %SSBO_Xor 0 Offset 0 OpMemberDecorate %SSBO_Xor 1 Offset 4 OpDecorate %SSBO_Xor Block OpDecorate %Xor DescriptorSet 0 - OpDecorate %Xor Binding 24 - OpDecorate %_arr_float_223 ArrayStride 4 + OpDecorate %Xor Binding 26 + OpDecorate %_arr_float_235 ArrayStride 4 OpMemberDecorate %SSBO_Not 0 Offset 0 OpMemberDecorate %SSBO_Not 1 Offset 4 OpDecorate %SSBO_Not Block OpDecorate %Not DescriptorSet 0 - OpDecorate %Not Binding 25 - OpDecorate %_arr_float_230 ArrayStride 4 + OpDecorate %Not Binding 27 + OpDecorate %_arr_float_242 ArrayStride 4 OpMemberDecorate %SSBO_Leq 0 Offset 0 OpMemberDecorate %SSBO_Leq 1 Offset 4 OpDecorate %SSBO_Leq Block OpDecorate %Leq DescriptorSet 0 - OpDecorate %Leq Binding 26 - OpDecorate %_arr_float_237 ArrayStride 4 + OpDecorate %Leq Binding 28 + OpDecorate %_arr_float_249 ArrayStride 4 OpMemberDecorate %SSBO_Lneq 0 Offset 0 OpMemberDecorate %SSBO_Lneq 1 Offset 4 OpDecorate %SSBO_Lneq Block OpDecorate %Lneq DescriptorSet 0 - OpDecorate %Lneq Binding 27 + OpDecorate %Lneq Binding 29 OpDecorate %_arr_float_SEL ArrayStride 4 OpMemberDecorate %SSBO_Sel 0 Offset 0 OpMemberDecorate %SSBO_Sel 1 Offset 4 OpDecorate %SSBO_Sel Block OpDecorate %Sel DescriptorSet 0 - OpDecorate %Sel Binding 28 - OpDecorate %249 SpecId 8 + OpDecorate %Sel Binding 30 + OpDecorate %262 SpecId 8 OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize OpDecorate %TRUE SpecId 0 OpDecorate %FALSE SpecId 1 @@ -394,17 +395,19 @@ %int_0 = OpConstant %int 0 %float_0 = OpConstant %float 0 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float - %28 = OpSpecConstantOp %uint IAdd %SONE %uint_0 - %ISUB = OpSpecConstantOp %uint ISub %UTWO %28 -%_arr_float_ISUB = OpTypeArray %float %ISUB - %SSBO_ISub = OpTypeStruct %_arr_float_ISUB %float + %SNEG_TWO = OpSpecConstant %int -2 + %29 = OpSpecConstantOp %uint IAdd %SNEG_TWO %uint_0 + %ISUB = OpSpecConstantOp %uint ISub %UTWO %29 + %uint_3 = OpConstant %uint 3 + %32 = OpSpecConstantOp %uint ISub %ISUB %uint_3 +%_arr_float_32 = OpTypeArray %float %32 + %SSBO_ISub = OpTypeStruct %_arr_float_32 %float %_ptr_StorageBuffer_SSBO_ISub = OpTypePointer StorageBuffer %SSBO_ISub %ISub = OpVariable %_ptr_StorageBuffer_SSBO_ISub StorageBuffer %IMUL = OpSpecConstantOp %uint IMul %UTWO %UTWO - %uint_3 = OpConstant %uint 3 - %37 = OpSpecConstantOp %uint ISub %IMUL %uint_3 -%_arr_float_37 = OpTypeArray %float %37 - %SSBO_IMul = OpTypeStruct %_arr_float_37 %float + %39 = OpSpecConstantOp %uint ISub %IMUL %uint_3 +%_arr_float_39 = OpTypeArray %float %39 + %SSBO_IMul = OpTypeStruct %_arr_float_39 %float %_ptr_StorageBuffer_SSBO_IMul = OpTypePointer StorageBuffer %SSBO_IMul %IMul = OpVariable %_ptr_StorageBuffer_SSBO_IMul StorageBuffer %UDIV = OpSpecConstantOp %uint UDiv %UTWO %UTWO @@ -412,248 +415,259 @@ %SSBO_UDiv = OpTypeStruct %_arr_float_UDIV %float %_ptr_StorageBuffer_SSBO_UDiv = OpTypePointer StorageBuffer %SSBO_UDiv %UDiv = OpVariable %_ptr_StorageBuffer_SSBO_UDiv StorageBuffer - %SNEG_TWO = OpSpecConstant %int -2 - %SDIV = OpSpecConstantOp %int SDiv %STWO %SNEG_TWO - %int_2 = OpConstant %int 2 - %52 = OpSpecConstantOp %int IAdd %SDIV %int_2 -%_arr_float_52 = OpTypeArray %float %52 - %SSBO_SDiv = OpTypeStruct %_arr_float_52 %float + %SNEG_THREE = OpSpecConstant %int -3 + %SDIV = OpSpecConstantOp %int SDiv %STWO %SNEG_THREE + %int_1 = OpConstant %int 1 + %54 = OpSpecConstantOp %int IAdd %SDIV %int_1 +%_arr_float_54 = OpTypeArray %float %54 + %SSBO_SDiv = OpTypeStruct %_arr_float_54 %float %_ptr_StorageBuffer_SSBO_SDiv = OpTypePointer StorageBuffer %SSBO_SDiv %SDiv = OpVariable %_ptr_StorageBuffer_SSBO_SDiv StorageBuffer - %uint_1 = OpConstant %uint 1 -%_arr_float_uint_1 = OpTypeArray %float %uint_1 - %SSBO_SRem = OpTypeStruct %_arr_float_uint_1 %float + %SREM = OpSpecConstantOp %int SRem %STWO %SNEG_THREE + %61 = OpSpecConstantOp %int ISub %SREM %int_1 +%_arr_float_61 = OpTypeArray %float %61 + %SSBO_SRem = OpTypeStruct %_arr_float_61 %float %_ptr_StorageBuffer_SSBO_SRem = OpTypePointer StorageBuffer %SSBO_SRem %SRem = OpVariable %_ptr_StorageBuffer_SSBO_SRem StorageBuffer - %SNEG_THREE = OpSpecConstant %int -3 %SMOD = OpSpecConstantOp %int SMod %STWO %SNEG_THREE - %66 = OpSpecConstantOp %int IAdd %SMOD %int_2 -%_arr_float_66 = OpTypeArray %float %66 - %SSBO_SMod = OpTypeStruct %_arr_float_66 %float + %int_2 = OpConstant %int 2 + %69 = OpSpecConstantOp %int IAdd %SMOD %int_2 +%_arr_float_69 = OpTypeArray %float %69 + %SSBO_SMod = OpTypeStruct %_arr_float_69 %float %_ptr_StorageBuffer_SSBO_SMod = OpTypePointer StorageBuffer %SSBO_SMod %SMod = OpVariable %_ptr_StorageBuffer_SSBO_SMod StorageBuffer %UMOD = OpSpecConstantOp %uint UMod %IADD %IMUL - %73 = OpSpecConstantOp %uint ISub %UMOD %uint_1 -%_arr_float_73 = OpTypeArray %float %73 - %SSBO_UMod = OpTypeStruct %_arr_float_73 %float + %uint_1 = OpConstant %uint 1 + %77 = OpSpecConstantOp %uint ISub %UMOD %uint_1 +%_arr_float_77 = OpTypeArray %float %77 + %SSBO_UMod = OpTypeStruct %_arr_float_77 %float %_ptr_StorageBuffer_SSBO_UMod = OpTypePointer StorageBuffer %SSBO_UMod %UMod = OpVariable %_ptr_StorageBuffer_SSBO_UMod StorageBuffer - %LSHL = OpSpecConstantOp %uint ShiftLeftLogical %IADD %ISUB + %83 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %LSHL = OpSpecConstantOp %uint ShiftLeftLogical %IADD %83 %uint_11 = OpConstant %uint 11 - %81 = OpSpecConstantOp %uint ISub %LSHL %uint_11 -%_arr_float_81 = OpTypeArray %float %81 - %SSBO_LShl = OpTypeStruct %_arr_float_81 %float + %86 = OpSpecConstantOp %uint ISub %LSHL %uint_11 +%_arr_float_86 = OpTypeArray %float %86 + %SSBO_LShl = OpTypeStruct %_arr_float_86 %float %_ptr_StorageBuffer_SSBO_LShl = OpTypePointer StorageBuffer %SSBO_LShl %LShl = OpVariable %_ptr_StorageBuffer_SSBO_LShl StorageBuffer - %RSHL = OpSpecConstantOp %uint ShiftRightLogical %IADD %ISUB + %92 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %RSHL = OpSpecConstantOp %uint ShiftRightLogical %IADD %92 %uint_2 = OpConstant %uint 2 - %89 = OpSpecConstantOp %uint ISub %RSHL %uint_2 -%_arr_float_89 = OpTypeArray %float %89 - %SSBO_RShl = OpTypeStruct %_arr_float_89 %float + %95 = OpSpecConstantOp %uint ISub %RSHL %uint_2 +%_arr_float_95 = OpTypeArray %float %95 + %SSBO_RShl = OpTypeStruct %_arr_float_95 %float %_ptr_StorageBuffer_SSBO_RShl = OpTypePointer StorageBuffer %SSBO_RShl %RShl = OpVariable %_ptr_StorageBuffer_SSBO_RShl StorageBuffer - %95 = OpSpecConstantOp %int IAdd %IADD %uint_0 - %96 = OpSpecConstantOp %int SNegate %95 - %97 = OpSpecConstantOp %int SNegate %SDIV - %RSHA = OpSpecConstantOp %int ShiftRightArithmetic %96 %97 + %101 = OpSpecConstantOp %int IAdd %IADD %uint_0 + %102 = OpSpecConstantOp %int SNegate %101 + %103 = OpSpecConstantOp %int ISub %int_1 %SDIV + %RSHA = OpSpecConstantOp %int ShiftRightArithmetic %102 %103 %int_4 = OpConstant %int 4 - %100 = OpSpecConstantOp %int IAdd %RSHA %int_4 -%_arr_float_100 = OpTypeArray %float %100 - %SSBO_RSha = OpTypeStruct %_arr_float_100 %float + %106 = OpSpecConstantOp %int IAdd %RSHA %int_4 +%_arr_float_106 = OpTypeArray %float %106 + %SSBO_RSha = OpTypeStruct %_arr_float_106 %float %_ptr_StorageBuffer_SSBO_RSha = OpTypePointer StorageBuffer %SSBO_RSha %RSha = OpVariable %_ptr_StorageBuffer_SSBO_RSha StorageBuffer + %112 = OpSpecConstantOp %uint ISub %ISUB %uint_3 %bool = OpTypeBool - %IEQ = OpSpecConstantOp %bool IEqual %IADD %ISUB - %int_1 = OpConstant %int 1 - %109 = OpSpecConstantOp %int Select %IEQ %int_2 %int_1 -%_arr_float_109 = OpTypeArray %float %109 - %SSBO_IEq = OpTypeStruct %_arr_float_109 %float + %IEQ = OpSpecConstantOp %bool IEqual %IADD %112 + %115 = OpSpecConstantOp %int Select %IEQ %int_2 %int_1 +%_arr_float_115 = OpTypeArray %float %115 + %SSBO_IEq = OpTypeStruct %_arr_float_115 %float %_ptr_StorageBuffer_SSBO_IEq = OpTypePointer StorageBuffer %SSBO_IEq %IEq = OpVariable %_ptr_StorageBuffer_SSBO_IEq StorageBuffer - %INEQ = OpSpecConstantOp %bool INotEqual %IADD %ISUB - %116 = OpSpecConstantOp %int Select %INEQ %int_1 %int_2 -%_arr_float_116 = OpTypeArray %float %116 - %SSBO_INeq = OpTypeStruct %_arr_float_116 %float + %121 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %INEQ = OpSpecConstantOp %bool INotEqual %IADD %121 + %123 = OpSpecConstantOp %int Select %INEQ %int_1 %int_2 +%_arr_float_123 = OpTypeArray %float %123 + %SSBO_INeq = OpTypeStruct %_arr_float_123 %float %_ptr_StorageBuffer_SSBO_INeq = OpTypePointer StorageBuffer %SSBO_INeq %INeq = OpVariable %_ptr_StorageBuffer_SSBO_INeq StorageBuffer - %ULT = OpSpecConstantOp %bool ULessThan %IADD %ISUB - %123 = OpSpecConstantOp %int Select %ULT %int_2 %int_1 -%_arr_float_123 = OpTypeArray %float %123 - %SSBO_Ult = OpTypeStruct %_arr_float_123 %float + %129 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %ULT = OpSpecConstantOp %bool ULessThan %IADD %129 + %131 = OpSpecConstantOp %int Select %ULT %int_2 %int_1 +%_arr_float_131 = OpTypeArray %float %131 + %SSBO_Ult = OpTypeStruct %_arr_float_131 %float %_ptr_StorageBuffer_SSBO_Ult = OpTypePointer StorageBuffer %SSBO_Ult %Ult = OpVariable %_ptr_StorageBuffer_SSBO_Ult StorageBuffer - %ULE = OpSpecConstantOp %bool ULessThanEqual %IADD %ISUB - %130 = OpSpecConstantOp %int Select %ULE %int_2 %int_1 -%_arr_float_130 = OpTypeArray %float %130 - %SSBO_Ule = OpTypeStruct %_arr_float_130 %float + %137 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %ULE = OpSpecConstantOp %bool ULessThanEqual %IADD %137 + %139 = OpSpecConstantOp %int Select %ULE %int_2 %int_1 +%_arr_float_139 = OpTypeArray %float %139 + %SSBO_Ule = OpTypeStruct %_arr_float_139 %float %_ptr_StorageBuffer_SSBO_Ule = OpTypePointer StorageBuffer %SSBO_Ule %Ule = OpVariable %_ptr_StorageBuffer_SSBO_Ule StorageBuffer - %UGT = OpSpecConstantOp %bool UGreaterThan %IADD %ISUB - %137 = OpSpecConstantOp %int Select %UGT %int_1 %int_2 -%_arr_float_137 = OpTypeArray %float %137 - %SSBO_Ugt = OpTypeStruct %_arr_float_137 %float + %145 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %UGT = OpSpecConstantOp %bool UGreaterThan %IADD %145 + %147 = OpSpecConstantOp %int Select %UGT %int_1 %int_2 +%_arr_float_147 = OpTypeArray %float %147 + %SSBO_Ugt = OpTypeStruct %_arr_float_147 %float %_ptr_StorageBuffer_SSBO_Ugt = OpTypePointer StorageBuffer %SSBO_Ugt %Ugt = OpVariable %_ptr_StorageBuffer_SSBO_Ugt StorageBuffer - %UGE = OpSpecConstantOp %bool UGreaterThanEqual %IADD %ISUB - %144 = OpSpecConstantOp %int Select %UGE %int_1 %int_2 -%_arr_float_144 = OpTypeArray %float %144 - %SSBO_Uge = OpTypeStruct %_arr_float_144 %float + %153 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %UGE = OpSpecConstantOp %bool UGreaterThanEqual %IADD %153 + %155 = OpSpecConstantOp %int Select %UGE %int_1 %int_2 +%_arr_float_155 = OpTypeArray %float %155 + %SSBO_Uge = OpTypeStruct %_arr_float_155 %float %_ptr_StorageBuffer_SSBO_Uge = OpTypePointer StorageBuffer %SSBO_Uge %Uge = OpVariable %_ptr_StorageBuffer_SSBO_Uge StorageBuffer - %SLT = OpSpecConstantOp %bool SLessThan %SMOD %int_1 - %151 = OpSpecConstantOp %int Select %SLT %int_1 %int_2 -%_arr_float_151 = OpTypeArray %float %151 - %SSBO_Slt = OpTypeStruct %_arr_float_151 %float + %SLT = OpSpecConstantOp %bool SLessThan %SMOD %SREM + %162 = OpSpecConstantOp %int Select %SLT %int_1 %int_2 +%_arr_float_162 = OpTypeArray %float %162 + %SSBO_Slt = OpTypeStruct %_arr_float_162 %float %_ptr_StorageBuffer_SSBO_Slt = OpTypePointer StorageBuffer %SSBO_Slt %Slt = OpVariable %_ptr_StorageBuffer_SSBO_Slt StorageBuffer - %SLE = OpSpecConstantOp %bool SLessThanEqual %SMOD %int_1 - %158 = OpSpecConstantOp %int Select %SLE %int_1 %int_2 -%_arr_float_158 = OpTypeArray %float %158 - %SSBO_Sle = OpTypeStruct %_arr_float_158 %float + %SLE = OpSpecConstantOp %bool SLessThanEqual %SMOD %SREM + %169 = OpSpecConstantOp %int Select %SLE %int_1 %int_2 +%_arr_float_169 = OpTypeArray %float %169 + %SSBO_Sle = OpTypeStruct %_arr_float_169 %float %_ptr_StorageBuffer_SSBO_Sle = OpTypePointer StorageBuffer %SSBO_Sle %Sle = OpVariable %_ptr_StorageBuffer_SSBO_Sle StorageBuffer - %SGT = OpSpecConstantOp %bool SGreaterThan %SMOD %int_1 - %165 = OpSpecConstantOp %int Select %SGT %int_2 %int_1 -%_arr_float_165 = OpTypeArray %float %165 - %SSBO_Sgt = OpTypeStruct %_arr_float_165 %float + %SGT = OpSpecConstantOp %bool SGreaterThan %SMOD %SREM + %176 = OpSpecConstantOp %int Select %SGT %int_2 %int_1 +%_arr_float_176 = OpTypeArray %float %176 + %SSBO_Sgt = OpTypeStruct %_arr_float_176 %float %_ptr_StorageBuffer_SSBO_Sgt = OpTypePointer StorageBuffer %SSBO_Sgt %Sgt = OpVariable %_ptr_StorageBuffer_SSBO_Sgt StorageBuffer - %SGE = OpSpecConstantOp %bool SGreaterThanEqual %SMOD %int_1 - %172 = OpSpecConstantOp %int Select %SGE %int_2 %int_1 -%_arr_float_172 = OpTypeArray %float %172 - %SSBO_Sge = OpTypeStruct %_arr_float_172 %float + %SGE = OpSpecConstantOp %bool SGreaterThanEqual %SMOD %SREM + %183 = OpSpecConstantOp %int Select %SGE %int_2 %int_1 +%_arr_float_183 = OpTypeArray %float %183 + %SSBO_Sge = OpTypeStruct %_arr_float_183 %float %_ptr_StorageBuffer_SSBO_Sge = OpTypePointer StorageBuffer %SSBO_Sge %Sge = OpVariable %_ptr_StorageBuffer_SSBO_Sge StorageBuffer %LOR = OpSpecConstantOp %bool LogicalOr %IEQ %SLT - %179 = OpSpecConstantOp %int Select %LOR %int_1 %int_2 -%_arr_float_179 = OpTypeArray %float %179 - %SSBO_Lor = OpTypeStruct %_arr_float_179 %float + %190 = OpSpecConstantOp %int Select %LOR %int_1 %int_2 +%_arr_float_190 = OpTypeArray %float %190 + %SSBO_Lor = OpTypeStruct %_arr_float_190 %float %_ptr_StorageBuffer_SSBO_Lor = OpTypePointer StorageBuffer %SSBO_Lor %Lor = OpVariable %_ptr_StorageBuffer_SSBO_Lor StorageBuffer %LAND = OpSpecConstantOp %bool LogicalAnd %IEQ %SLT - %186 = OpSpecConstantOp %int Select %LAND %int_2 %int_1 -%_arr_float_186 = OpTypeArray %float %186 - %SSBO_Land = OpTypeStruct %_arr_float_186 %float + %197 = OpSpecConstantOp %int Select %LAND %int_2 %int_1 +%_arr_float_197 = OpTypeArray %float %197 + %SSBO_Land = OpTypeStruct %_arr_float_197 %float %_ptr_StorageBuffer_SSBO_Land = OpTypePointer StorageBuffer %SSBO_Land %Land = OpVariable %_ptr_StorageBuffer_SSBO_Land StorageBuffer %LNOT = OpSpecConstantOp %bool LogicalNot %LOR - %193 = OpSpecConstantOp %int Select %LNOT %int_2 %int_1 -%_arr_float_193 = OpTypeArray %float %193 - %SSBO_Lnot = OpTypeStruct %_arr_float_193 %float + %204 = OpSpecConstantOp %int Select %LNOT %int_2 %int_1 +%_arr_float_204 = OpTypeArray %float %204 + %SSBO_Lnot = OpTypeStruct %_arr_float_204 %float %_ptr_StorageBuffer_SSBO_Lnot = OpTypePointer StorageBuffer %SSBO_Lnot %Lnot = OpVariable %_ptr_StorageBuffer_SSBO_Lnot StorageBuffer %AND = OpSpecConstantOp %uint BitwiseAnd %IADD %IADD - %200 = OpSpecConstantOp %uint ISub %AND %uint_5 -%_arr_float_200 = OpTypeArray %float %200 - %SSBO_And = OpTypeStruct %_arr_float_200 %float + %211 = OpSpecConstantOp %uint ISub %AND %uint_5 +%_arr_float_211 = OpTypeArray %float %211 + %SSBO_And = OpTypeStruct %_arr_float_211 %float %_ptr_StorageBuffer_SSBO_And = OpTypePointer StorageBuffer %SSBO_And %And = OpVariable %_ptr_StorageBuffer_SSBO_And StorageBuffer - %OR = OpSpecConstantOp %uint BitwiseOr %IADD %ISUB + %217 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %OR = OpSpecConstantOp %uint BitwiseOr %IADD %217 %uint_6 = OpConstant %uint 6 - %208 = OpSpecConstantOp %uint ISub %OR %uint_6 -%_arr_float_208 = OpTypeArray %float %208 - %SSBO_Or = OpTypeStruct %_arr_float_208 %float + %220 = OpSpecConstantOp %uint ISub %OR %uint_6 +%_arr_float_220 = OpTypeArray %float %220 + %SSBO_Or = OpTypeStruct %_arr_float_220 %float %_ptr_StorageBuffer_SSBO_Or = OpTypePointer StorageBuffer %SSBO_Or %Or = OpVariable %_ptr_StorageBuffer_SSBO_Or StorageBuffer %XOR = OpSpecConstantOp %uint BitwiseXor %IADD %IADD - %215 = OpSpecConstantOp %uint IAdd %XOR %uint_1 -%_arr_float_215 = OpTypeArray %float %215 - %SSBO_Xor = OpTypeStruct %_arr_float_215 %float + %227 = OpSpecConstantOp %uint IAdd %XOR %uint_1 +%_arr_float_227 = OpTypeArray %float %227 + %SSBO_Xor = OpTypeStruct %_arr_float_227 %float %_ptr_StorageBuffer_SSBO_Xor = OpTypePointer StorageBuffer %SSBO_Xor %Xor = OpVariable %_ptr_StorageBuffer_SSBO_Xor StorageBuffer %NOT = OpSpecConstantOp %uint Not %XOR %uint_4294967294 = OpConstant %uint 4294967294 - %223 = OpSpecConstantOp %uint ISub %NOT %uint_4294967294 -%_arr_float_223 = OpTypeArray %float %223 - %SSBO_Not = OpTypeStruct %_arr_float_223 %float + %235 = OpSpecConstantOp %uint ISub %NOT %uint_4294967294 +%_arr_float_235 = OpTypeArray %float %235 + %SSBO_Not = OpTypeStruct %_arr_float_235 %float %_ptr_StorageBuffer_SSBO_Not = OpTypePointer StorageBuffer %SSBO_Not %Not = OpVariable %_ptr_StorageBuffer_SSBO_Not StorageBuffer %LEQ = OpSpecConstantOp %bool LogicalEqual %LAND %LNOT - %230 = OpSpecConstantOp %int Select %LEQ %int_1 %int_2 -%_arr_float_230 = OpTypeArray %float %230 - %SSBO_Leq = OpTypeStruct %_arr_float_230 %float + %242 = OpSpecConstantOp %int Select %LEQ %int_1 %int_2 +%_arr_float_242 = OpTypeArray %float %242 + %SSBO_Leq = OpTypeStruct %_arr_float_242 %float %_ptr_StorageBuffer_SSBO_Leq = OpTypePointer StorageBuffer %SSBO_Leq %Leq = OpVariable %_ptr_StorageBuffer_SSBO_Leq StorageBuffer %LNEQ = OpSpecConstantOp %bool LogicalNotEqual %LAND %LNOT - %237 = OpSpecConstantOp %int Select %LNEQ %int_2 %int_1 -%_arr_float_237 = OpTypeArray %float %237 - %SSBO_Lneq = OpTypeStruct %_arr_float_237 %float + %249 = OpSpecConstantOp %int Select %LNEQ %int_2 %int_1 +%_arr_float_249 = OpTypeArray %float %249 + %SSBO_Lneq = OpTypeStruct %_arr_float_249 %float %_ptr_StorageBuffer_SSBO_Lneq = OpTypePointer StorageBuffer %SSBO_Lneq %Lneq = OpVariable %_ptr_StorageBuffer_SSBO_Lneq StorageBuffer - %SEL = OpSpecConstantOp %uint Select %IEQ %IADD %ISUB + %255 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %SEL = OpSpecConstantOp %uint Select %IEQ %IADD %255 %_arr_float_SEL = OpTypeArray %float %SEL %SSBO_Sel = OpTypeStruct %_arr_float_SEL %float %_ptr_StorageBuffer_SSBO_Sel = OpTypePointer StorageBuffer %SSBO_Sel %Sel = OpVariable %_ptr_StorageBuffer_SSBO_Sel StorageBuffer ; default value should be respected, even if no compiler write things other than 1 - %249 = OpSpecConstant %uint 4 + %262 = OpSpecConstant %uint 4 %v3uint = OpTypeVector %uint 3 -%gl_WorkGroupSize = OpSpecConstantComposite %v3uint %249 %uint_1 %uint_1 +%gl_WorkGroupSize = OpSpecConstantComposite %v3uint %262 %uint_1 %uint_1 %TRUE = OpSpecConstantTrue %bool %FALSE = OpSpecConstantFalse %bool %main = OpFunction %void None %3 %5 = OpLabel %27 = OpAccessChain %_ptr_StorageBuffer_float %IAdd %int_0 %int_0 OpStore %27 %float_0 - %34 = OpAccessChain %_ptr_StorageBuffer_float %ISub %int_0 %int_0 - OpStore %34 %float_0 - %42 = OpAccessChain %_ptr_StorageBuffer_float %IMul %int_0 %int_0 - OpStore %42 %float_0 - %48 = OpAccessChain %_ptr_StorageBuffer_float %UDiv %int_0 %int_0 - OpStore %48 %float_0 - %57 = OpAccessChain %_ptr_StorageBuffer_float %SDiv %int_0 %int_0 - OpStore %57 %float_0 - %63 = OpAccessChain %_ptr_StorageBuffer_float %SRem %int_0 %int_0 - OpStore %63 %float_0 - %71 = OpAccessChain %_ptr_StorageBuffer_float %SMod %int_0 %int_0 - OpStore %71 %float_0 - %78 = OpAccessChain %_ptr_StorageBuffer_float %UMod %int_0 %int_0 - OpStore %78 %float_0 - %86 = OpAccessChain %_ptr_StorageBuffer_float %LShl %int_0 %int_0 - OpStore %86 %float_0 - %94 = OpAccessChain %_ptr_StorageBuffer_float %RShl %int_0 %int_0 - OpStore %94 %float_0 - %105 = OpAccessChain %_ptr_StorageBuffer_float %RSha %int_0 %int_0 - OpStore %105 %float_0 - %114 = OpAccessChain %_ptr_StorageBuffer_float %IEq %int_0 %int_0 - OpStore %114 %float_0 - %121 = OpAccessChain %_ptr_StorageBuffer_float %INeq %int_0 %int_0 - OpStore %121 %float_0 - %128 = OpAccessChain %_ptr_StorageBuffer_float %Ult %int_0 %int_0 + %37 = OpAccessChain %_ptr_StorageBuffer_float %ISub %int_0 %int_0 + OpStore %37 %float_0 + %44 = OpAccessChain %_ptr_StorageBuffer_float %IMul %int_0 %int_0 + OpStore %44 %float_0 + %50 = OpAccessChain %_ptr_StorageBuffer_float %UDiv %int_0 %int_0 + OpStore %50 %float_0 + %59 = OpAccessChain %_ptr_StorageBuffer_float %SDiv %int_0 %int_0 + OpStore %59 %float_0 + %66 = OpAccessChain %_ptr_StorageBuffer_float %SRem %int_0 %int_0 + OpStore %66 %float_0 + %74 = OpAccessChain %_ptr_StorageBuffer_float %SMod %int_0 %int_0 + OpStore %74 %float_0 + %82 = OpAccessChain %_ptr_StorageBuffer_float %UMod %int_0 %int_0 + OpStore %82 %float_0 + %91 = OpAccessChain %_ptr_StorageBuffer_float %LShl %int_0 %int_0 + OpStore %91 %float_0 + %100 = OpAccessChain %_ptr_StorageBuffer_float %RShl %int_0 %int_0 + OpStore %100 %float_0 + %111 = OpAccessChain %_ptr_StorageBuffer_float %RSha %int_0 %int_0 + OpStore %111 %float_0 + %120 = OpAccessChain %_ptr_StorageBuffer_float %IEq %int_0 %int_0 + OpStore %120 %float_0 + %128 = OpAccessChain %_ptr_StorageBuffer_float %INeq %int_0 %int_0 OpStore %128 %float_0 - %135 = OpAccessChain %_ptr_StorageBuffer_float %Ule %int_0 %int_0 - OpStore %135 %float_0 - %142 = OpAccessChain %_ptr_StorageBuffer_float %Ugt %int_0 %int_0 - OpStore %142 %float_0 - %149 = OpAccessChain %_ptr_StorageBuffer_float %Uge %int_0 %int_0 - OpStore %149 %float_0 - %156 = OpAccessChain %_ptr_StorageBuffer_float %Slt %int_0 %int_0 - OpStore %156 %float_0 - %163 = OpAccessChain %_ptr_StorageBuffer_float %Sle %int_0 %int_0 - OpStore %163 %float_0 - %170 = OpAccessChain %_ptr_StorageBuffer_float %Sgt %int_0 %int_0 - OpStore %170 %float_0 - %177 = OpAccessChain %_ptr_StorageBuffer_float %Sge %int_0 %int_0 - OpStore %177 %float_0 - %184 = OpAccessChain %_ptr_StorageBuffer_float %Lor %int_0 %int_0 - OpStore %184 %float_0 - %191 = OpAccessChain %_ptr_StorageBuffer_float %Land %int_0 %int_0 - OpStore %191 %float_0 - %198 = OpAccessChain %_ptr_StorageBuffer_float %Lnot %int_0 %int_0 - OpStore %198 %float_0 - %205 = OpAccessChain %_ptr_StorageBuffer_float %And %int_0 %int_0 - OpStore %205 %float_0 - %213 = OpAccessChain %_ptr_StorageBuffer_float %Or %int_0 %int_0 - OpStore %213 %float_0 - %220 = OpAccessChain %_ptr_StorageBuffer_float %Xor %int_0 %int_0 - OpStore %220 %float_0 - %228 = OpAccessChain %_ptr_StorageBuffer_float %Not %int_0 %int_0 - OpStore %228 %float_0 - %235 = OpAccessChain %_ptr_StorageBuffer_float %Leq %int_0 %int_0 - OpStore %235 %float_0 - %242 = OpAccessChain %_ptr_StorageBuffer_float %Lneq %int_0 %int_0 - OpStore %242 %float_0 - %248 = OpAccessChain %_ptr_StorageBuffer_float %Sel %int_0 %int_0 - OpStore %248 %float_0 + %136 = OpAccessChain %_ptr_StorageBuffer_float %Ult %int_0 %int_0 + OpStore %136 %float_0 + %144 = OpAccessChain %_ptr_StorageBuffer_float %Ule %int_0 %int_0 + OpStore %144 %float_0 + %152 = OpAccessChain %_ptr_StorageBuffer_float %Ugt %int_0 %int_0 + OpStore %152 %float_0 + %160 = OpAccessChain %_ptr_StorageBuffer_float %Uge %int_0 %int_0 + OpStore %160 %float_0 + %167 = OpAccessChain %_ptr_StorageBuffer_float %Slt %int_0 %int_0 + OpStore %167 %float_0 + %174 = OpAccessChain %_ptr_StorageBuffer_float %Sle %int_0 %int_0 + OpStore %174 %float_0 + %181 = OpAccessChain %_ptr_StorageBuffer_float %Sgt %int_0 %int_0 + OpStore %181 %float_0 + %188 = OpAccessChain %_ptr_StorageBuffer_float %Sge %int_0 %int_0 + OpStore %188 %float_0 + %195 = OpAccessChain %_ptr_StorageBuffer_float %Lor %int_0 %int_0 + OpStore %195 %float_0 + %202 = OpAccessChain %_ptr_StorageBuffer_float %Land %int_0 %int_0 + OpStore %202 %float_0 + %209 = OpAccessChain %_ptr_StorageBuffer_float %Lnot %int_0 %int_0 + OpStore %209 %float_0 + %216 = OpAccessChain %_ptr_StorageBuffer_float %And %int_0 %int_0 + OpStore %216 %float_0 + %225 = OpAccessChain %_ptr_StorageBuffer_float %Or %int_0 %int_0 + OpStore %225 %float_0 + %232 = OpAccessChain %_ptr_StorageBuffer_float %Xor %int_0 %int_0 + OpStore %232 %float_0 + %240 = OpAccessChain %_ptr_StorageBuffer_float %Not %int_0 %int_0 + OpStore %240 %float_0 + %247 = OpAccessChain %_ptr_StorageBuffer_float %Leq %int_0 %int_0 + OpStore %247 %float_0 + %254 = OpAccessChain %_ptr_StorageBuffer_float %Lneq %int_0 %int_0 + OpStore %254 %float_0 + %261 = OpAccessChain %_ptr_StorageBuffer_float %Sel %int_0 %int_0 + OpStore %261 %float_0 OpReturn OpFunctionEnd diff --git a/tests/spec_constant/test_32bit.spv.dis.patch b/tests/spec_constant/test_32bit.spv.dis.patch index c1283b9f..0186613d 100644 --- a/tests/spec_constant/test_32bit.spv.dis.patch +++ b/tests/spec_constant/test_32bit.spv.dis.patch @@ -3,8 +3,12 @@ --- > ; should ignore this if working with WorkGroupSize builtin > OpExecutionMode %main LocalSize 2 3 4 -587c588,589 -< %249 = OpSpecConstant %uint 1 +425c426 +< %SREM = OpSpecConstantOp %int SMod %STWO %SNEG_THREE +--- +> %SREM = OpSpecConstantOp %int SRem %STWO %SNEG_THREE +601c602,603 +< %262 = OpSpecConstant %uint 1 --- > ; default value should be respected, even if no compiler write things other than 1 -> %249 = OpSpecConstant %uint 4 +> %262 = OpSpecConstant %uint 4 diff --git a/tests/spec_constant/test_64bit.spv b/tests/spec_constant/test_64bit.spv index 672de13b20ebe09f082b97b872b032b0d1185d3c..e739b65f8178840aad49c43b8e662203d6591f78 100644 GIT binary patch literal 11944 zcmZvi37DQ$b;mz4GuanH62eX*5X2xt2%89GAj4$f%Z$vIPd0Ig$q*u0SP~Q$81|)9 ztyr~c+o{T;fM{10wJohyyYKtHx^#7K73uGHzxO03_u=v!&iViEx#xfGeV6YY9{Oe+ zH>)*pP^;CN)morqEN;zc8S3ZZ=e1@QJlyWIPq}5!)>GD=ajJO>TYb7Rx2Sb|Yk+tL zwsZ6LUGmQMWAZbxS=elB4mKCF_Izvswh&u{9gHo;4#AdSOR;6xq1bZlFzj&b2<%Ag zDC}tL80=VV1-2497)5)rmOgsvBN9Ky2K(t^xIHmEHa6TIn%HvVjT5)*xoyYf#E$K| zCMULTzj<=Yp6$0znm0S;ZQr$J$KI_uVStRhZ}Cge=!}gH;n;tF>p1bI%f|vAPtZ;C zCy3MhD)7kQ`t`m1f!2uxoz8`06C;CLw-V2!rkvx}%{#!o9IxBfy*qc_hF8~pH%q_+ zt(Ss3qeH_JN$VtYI^7F#CFf=46s^wQ*AuHH=Ljuvt>v{I=`AVRtHm3;ZCt5)GQL-L zpj^lDRo`} z?w!qs@gc69=jV;yNm{3gJ)6#cEjdSMiEAzI{bot2yGA@dv=LXdPZyWEWb^SK2M$Al2UiAc;nc<`{oRBsk?D^+&6NLs4K4P`iypZOG@1{!QE8%Ea$D;-CtME z5p~6NU7!1ANvV4_xZT;%#+7q82Vd&8JJ-iOBIk&@;<~Qyl4eP%`%3V5s(UWD)E(bn zSI!Z2#dY2JaLtlZ_f-XN7{rx+&%;OE&BR_eIY-nL*L8j8QP(BZ>1&;j9~ru=)VzSW z)EpVQ$$4waIijZcz?yyK9qJPA+jY#3j8c%{b3cgh)f}C)s5RvrQB!rqLs)9cIijZcz?yyK9q$tBd82mQL#3WC%ckBWVW}tQh z-eS1!j>%H*V&manf5XJRdfWE(C+CQI;<}!{JzbXA-v;C1UVkIRO}%~n$vL8)xUT2# zSa(~mze|Wa&G}twT%OJS=O^cgdg8jCzlojZ{Csda&H4EebtSe&q)YKI)0-@q=h&+C}qG~OM;6}%09@nE|nG0gl+@UEZH;Nu$H z*WlwDJka118tnIz>#xTf_hTDSI1%r#jw3iVen(=*_HRBsKYs!VDwX&vIO?B+y4fw2aGT4zd1RMv6^vxb`oce)4`6c zAy;e2g@)g@SwpNw+=sh}v&I=e(O52hFq;77aH@4vxZm= z&rA(}gtNwZU`N)Ft2N|8V*zp25Ub&tsc{QFYg_Lz>qxZM){(TI= zJFLz>#~33g-+ zxmrUmG_033#F}TO#{GEL$9KvD#QqM)J#k$#k1P4x8tj@Ss62>Y$(Qa!c;iEfe+0h* zTSond@#`@2*YN!&wjZ%0IQL}Fj!E0vAM2s-aT%|tL>b7d>KAC`}-i+{^Z@G zxWD0|?rQKom_2C0|0J<`&WGL`h}CmWy_505srOT0_2ktPd#&W6?#qeq!$Qw}+yJ(& zbJjftADnf68f*=D>xySKT%7wWz|W_1e;9l!=5y#h?tEO=Y2tiun)@@@6y};~%)WNu z?aMj)It?G3_k+*OhcIi|=ZEq0G4t$GJgec{zdCEMhp^}=_>aJO-p)^B>hHv>@0|Ll zWODJT-03)wnpg189W9z19L>~^Zo`d3)H6w+H9!;VgV`_V6Uw9^~yo zJh$PZ?o(jvo`iWn2Y)v4uVeORPCSE86VJmOk^6CCYq-XFd%F>DZ_e49-G4K;hosp=H2)U#J6M4+k?5kh}pw5b}AP9tB8LMbB#H15B?HyKjw(s zPZ3XHu5sRd+>Cc0&bg2C@WHu{PlN4Q-hGG{G+dm|XTbIr*MBJ|_$=6Y{rQ;pm-{q# zEl;j{`Yh&s==@{YG-gk?;O)tId%6H0oIQOGY)|s`BwpBX(bMO_xu@u59sHA+y_gfd z{4%k~fjczbc)UIy{O*~_nh?M2>R#EUSw=;c?5U#yo4;l20l#hmEnIbwTp z-ae)=d)bS(7w7HeB7AW6;(eg5yuFAIZn)^h=kYEqu2r1NdN}W8dod?^`2w-MIG=mD z6>Klg+shC>ID7db*k0uAMZCD-qL<$QzgRC9!#{&<&QD{HVV=ty@%G}p zy$s`nvzIS}?M2>R#D_Fo^zxhF7wcsMyzd`-F(-QYEn<6dej1Bj-b8FK&fCifJ~(^% zZLqz_+lzQf!^O3@1nhfeEw-lk-t+Q1#A-S}jfLiI#A-UP=B4=H)cjqrn(}Ijmo{8z zw!yxmYR%t+Q`7lrEHvLttfup7Zo~(t=I?{mlvh){tl>g)6#O(+YyJV8n$D{?jd`8l zf>+adHOKJ5sriRsHRaV5AKGxC`D*YpSgrX-aB4cAHQx$W(|I*7!w0A4AA{ADS5v&a z;X-p9Y)#*DUc0!5{)AXf=clna+qV&`>Aad9d~j<1DOgQ;HN}TDTxf0rKaSO!e+H+f z^Ld}QgVl6i%`QGTHUAu}ro5Ws!yC@uE#LF6!Jfd}Pweq8h}Cm0>)ioX&w2GO#|Nk0 zUxL+>S5JII!@0+I5MP1$epuC5@P7sNS$6&r%zI}Fuby-2U5TH<R-o zm|WC-E%6tz`YiqdZVGeW>!6N%(0HTdAv`$w>~<<%1(-EdxO_xw7{_pNnfzyCyB z|9$q)aMm{8dG+tctM8op6ZqiN{}-_O^6HC^X*l=$Eb+D2M=y?8a9S91$KI5oct zR#RS0@d`{XuItx`J-?H%_ZNOvIsdK1YMzg+!pu|iKD?UFt2v1ePR*}_tuL>pcxA(_ z0l%I2eykr`&cFX1FV}~i&e@9}z|8qjW2Z9fHMtHut%2?#(oLS(b zsvNnTGaKx0K)%Q1a?TvE@9CT)mviQVeXr&mxtuc(yrRmH%Q^GGE2|tibDrnIosIoJ Dmbf(x literal 11616 zcmZ9Q2b`T%nTM}al0Zm<5L$=<0TGlE0wOho876}_GdMRFA|jKJ86Y}IC`l9xj))@m z-h1!8_hs$9yKC9iUCS2Bu617-A_z_hK(|?4_SdeJA%iz%EAGlOyBfBkkeIZP#BvdDHHjXQn4-w(p#toZ5cl z^tRpG_fETRL0Y$c=eC(WQ+dH4EAoA-kA=}09~&ld{{yXis5f0c9{M z^kC~=bkF=>uB$i()T3w#%`Nb`kqYg_1(B1^B;&xxKRSn8VPce1&p^gR>ZO?}UD-oD*^ef1pCS6%n@d){19`ra4a z?rfNQPR>S`zU|I+@to*6qOZE{>u*PMN$Gn(^hD}=4!ZQ6*w^a3S-fV>D#A&voQp&#`Hn+EdRFJ=an1-*ce+29NeGp-X>jh&A2zrqa_N zjncC_vzxN?)N@2n_5MBk%Wt}u*zf+#ciY3IpAT)*Z<@07D-SYt^i$XUmf>}0rb|D* z2CeQ$Z+{n4_xfEsw?92c^i$XU{9DuI68AS^J<{9X2I{8Y-2U_&(NA6X^Y2#o+TQ*~ zsXNX2U1D9noBPgB&k_C9b-(3!o#y-=VBMUbU!tbp-2TcJ3qSg)>wf+{?KJ1N(YiUm zG3&Cwednj=h<@t2-wM1=bAJAT>on(gsdca4-2U_&(NA6X^Y478IX@rh_V`43UMBSI z*WPs_WqDro9MMl*_w${>OZ=X6tcS+RV>XDh3Ek_tb>|ed-xEDY^i=QPbD+F~w0oD7 zzFpR|$HvR0_Pq?<>$`K;Zfg7LIijz+?(2I^yLSm)`dgQy-L5@1Q({n^Wb=_|jo|o8flDgge#%`f5{o3W{u=LY& zM87T6bwA%Jy~Oj{YMp*#uSWNJ?wtFL)pJBo_5M8vTC4Hey-UhIx1l@3ZR)|6&tU1< znVz96`_ywpPxbyi`^!78m$*;AY?~&!!(OAlhJ5i*yQ49JK9=nDeU0|rRPDQ>^T#!M zu+hgidS0WiC0h>=8z97csC^va*;CJTBXoCNFlD(9hfMV`MfLP`)R__Qq?r-#rJ11@ z47r)1mf^l+ZYO6(yq{)9yrX7@UNAhP%uvgS`G-tWQH={u?;GxchwUNGlVXQo4IcP^_=+z9pU>ro98EP4xnT#9AnQ=SdVsOhF;Ck3&t|)%uvhl z%w+5(XU4^7M`q~N4833+Or05O8J?Mphm$j71KN=pdNo5Y7`}sNhFXSaDB}_2%(w*Y z$PB%jp%;wh)S01{;hD+s|G{KN8|}ypy_%sH4Byo=LoLHIlkrG$W{ja7nW0xR^n$U1 zIy2NVJTn=OB4@^>Xh&w~)eOC0_)ec0Y8jrHj7O6*V*>5S485A67mUNHGea%IGn4Tc za%OBoJ2FGBX6Oau2v@EKBDH(;UR>iIuOoY{bMEn8i|d!%NZbLEk;7 zJ%7FEdv9u=_t=AdABwiGbN0OtIXwHm3~dj6`>N+PUOc;}p#S=}-jL;Iaw>5<;dASJ zd{!@~?jszr_7&8#gx5Ilz8*$)U(UI&)5zhuuUDeom%jT_&nNWa8GIFWJlo;DI(c$t z&~jWW=X7#-a$bYBr@kEZg2s#cUxU7@y8koqJO}UJ`MB5DQqL03$Gz^Lb`Q?EhqdJJ z+{5e8?m^!@s1KO)df)Fe(RUDjw@xDBGk-m`&yw@rqxZa%EYCT4XOY8`_Xe~)eR=8w z8!!6a7yT(hp5Kc&-#1b(Bpk8!P1NqeYn*ovyU6arIrnfjIXw69X0&_IcMod&_RgVq z&-X*$Nz{9I3tk`Lh&{ZO+C6xU^X}n#vU_mOJ)A=h&po^iEl=M)gpNHt1^?~DEa4uW zL9A_lliopn3*mft?`*tNi`V;}oJ;+WgzKG;@5#HU2MCAvAnV=4Ea5fIdk;5|y$9#K zhx5qcc@OVFyI+0pLA|K)mUBw)rMAEMe8O|i=PCDnM0}6d@-5SQKjCNRH9p6#aX&Yb z-H-F`=K^wg?&kw&_oMHA)QcN0_HiNlEkx`im>AXC-GH)WwbYA8%zr@3)R(C~r163|iuOBl24U}bhVG=6>3n8B z0xi>dnU|2mlj(Org}x=1#=wj?^VtG9G*<)GxJesna<0+ zlpLPS&!c7P%TyoMc)@%i`t^jrH={&+o?oDr>3lxhN26srFLQz%p3E)y7TM6f%P53+eSh76lSsbeGuB`Sl)?5yf=J>l*p zgL-A-Mc)UbKSR{_{B68h!ueMb@*YRFw{!BYB!?&OJ7{_O^3+E+o}Z~_{1C!t-@b9b z-=+4QnKXC5|3vNmy54#DYWdE|zlt25{C`Hv*O#we)p*{o&(tLGTEgemXDFVl?@{|) zIsZQ5<%G<~lVv(Da|<~CtUODCQf74v!5nTZ|ZBP&*GVQ61k6X+(G;a^&|2SylA^B450YK>lAa~Im*&-|?F ; should ignore this if working with WorkGroupSize builtin > OpExecutionMode %main LocalSize 2 3 4 -376c378 +377c379 < %int = OpTypeInt 32 1 --- > %int = OpTypeInt 64 1 -380c382,383 +381c383,384 < %uint = OpTypeInt 32 0 --- > %uint_orig = OpTypeInt 32 0 > %uint = OpTypeInt 64 0 422a426 -> %uint_orig_1 = OpConstant %uint 1 -587,589c591,594 -< %249 = OpSpecConstant %uint 1 +> %uint_orig_1 = OpConstant %uint_orig 1 +425c430 +< %SREM = OpSpecConstantOp %int SMod %STWO %SNEG_THREE +--- +> %SREM = OpSpecConstantOp %int SRem %STWO %SNEG_THREE +577,578c582,583 +< %uint_4294967294 = OpConstant %uint 4294967294 +< %235 = OpSpecConstantOp %uint ISub %NOT %uint_4294967294 +--- +> %uint_18446744073709551614 = OpConstant %uint 18446744073709551614 +> %235 = OpSpecConstantOp %uint ISub %NOT %uint_18446744073709551614 +601,603c605,608 +< %262 = OpSpecConstant %uint 1 < %v3uint = OpTypeVector %uint 3 -< %gl_WorkGroupSize = OpSpecConstantComposite %v3uint %249 %uint_1 %uint_1 +< %gl_WorkGroupSize = OpSpecConstantComposite %v3uint %262 %uint_1 %uint_1 --- > ; default value should be respected, even if no compiler write things other than 1 -> %249 = OpSpecConstant %uint_orig 4 +> %262 = OpSpecConstant %uint_orig 4 > %v3uint_orig = OpTypeVector %uint_orig 3 -> %gl_WorkGroupSize = OpSpecConstantComposite %v3uint_orig %249 %uint_orig_1 %uint_orig_1 +> %gl_WorkGroupSize = OpSpecConstantComposite %v3uint_orig %262 %uint_orig_1 %uint_orig_1 diff --git a/tests/spec_constant/test_convert.glsl b/tests/spec_constant/test_convert.glsl index 50902d69..ad737005 100644 --- a/tests/spec_constant/test_convert.glsl +++ b/tests/spec_constant/test_convert.glsl @@ -6,7 +6,8 @@ layout(local_size_x = 1) in; layout(constant_id = 0) const int64_t SONE = 1; layout(constant_id = 1) const uint64_t UONE = 1; -layout(constant_id = 2) const double DZERO = 0; +layout(constant_id = 2) const float F_ONE = 1.0; +layout(constant_id = 3) const double D_ONE = 1.0; const uint U_SONE = uint(SONE); const uint U_UONE = uint(UONE); @@ -14,8 +15,8 @@ const uint U_UONE = uint(UONE); const int S_SONE = int(SONE); const int S_UONE = int(UONE); -const float FZERO = float(DZERO); -const double DZERO2 = double(FZERO); +const float F_ONE2 = float(D_ONE); +const double D_ONE2 = double(F_ONE); #define DUMMY_SSBO(name, bind, size) layout(std430, set = 0, binding = bind) buffer SSBO_##name { float val[size]; float dummy; } name @@ -26,8 +27,8 @@ DUMMY_SSBO(S_Uone, 3, S_UONE); void main() { - U_Sone.val[0] = FZERO; - U_Uone.val[0] = FZERO; - S_Sone.val[0] = FZERO; - S_Uone.val[0] = FZERO; + U_Sone.val[0] = F_ONE; + U_Uone.val[0] = F_ONE; + S_Sone.val[0] = F_ONE2; + S_Uone.val[0] = F_ONE2; } \ No newline at end of file diff --git a/tests/spec_constant/test_convert.spv b/tests/spec_constant/test_convert.spv index 20deb2315255e7213f19607773290d1873bddd56..fd6b7febd84b93a20295ddc7761e6a4d5a56c587 100644 GIT binary patch literal 2112 zcmZ9N+fNfw5XKL^P!PF^fEUC?yn|>+B_<|5Z|91Q!l@jj=0&P`{0t=_Ef zjnd9u_4O;!Zow7Vva>}u>&kjA$a<}$4_}f^%PO)N*^&_F%QAG#ii!jOOGL@dyIS2J zfBWi3r>#yr^zqL@H)$uSZw-_5v=^sI+ou76ANx)+jN55)9^*F?_$B>z_pB2-l;siT51v*0X5-7THr0ocb0J7>M#g?8fbZpK$KJTLso=R%w>a31I`X8t*Y?vn6W_r!GJ zSf&e})TJLMKD(0X(u-zL&kZp3h_twHEQ<@Cj7yKlSF*S(!XJZr7Byp8efxR+H#7hL z^{jz&-K%=wSf&e})Mc)kK|M>-$#kVt(|e?U++l&&wet>m|DTm9{bOzC+ZD$hIQ(jw zPyCn-V!%C+u?%nJFvIkc`{qwC!5IFxw1+uZ-@+WMcVP~27L)s74q$RHjoW$-HLQoB zhV?PjfHMtx8ft*iuycBhUQtF}ceIC^*1u5GdKhZLSxovFYJ$-;jk|j0n?!vpy0xKw zOQ)Rkyr!p3?U8I%Io;QOBqPs#^&1?{1U`{Cj0N7(9?7O;RowxjIh1jCXMD%(8NQrt$d7p=AI>&~nIq#OVcr8A_I8Y!FEBc2Ka{cdg^9&{Id^%;{YQGj7oOao zYCn>(s26PW2S+`TcD^S+WSo&FGf511@?_SGL+6<=I`HHPrq^)xj`)_?J0d1MA|^aB znJwdp`COR$@Wcc&V{r6wNBfbCI(TN@^7Z==%`9L2-bW%iv)V*m)kbf4hkS1?Wt>@W zm{($OMt;npapbovoad6~2WB4O)^)z8J(4kdHWM%PJSE$eF6YcEoEbS%3*Ra7rk4le znB9VmMZ7;k{GYy89D2MeV=kBl?47*exNko9^h{4eAGpxxv2bO=2afNv#d#r2onag} KeEzDsH?n`P7MUji literal 2064 zcmZ9N+iO!n5XQH;G_AFlSlfE3HMQPbgOpeVL8=(zLoi@0h%bkb9O!{0#^kivxBhMZ zRlW#*zs;GtWMP>7zMY-R&g3MY+bg-^oO7<^%1@-U$}Z<%(AP4(B)#P3J>O`yo7G9$ ztJYq<6zx`A9_7zg-J&aMpOXwa$q>FEnU|C#3z9V<&dUZqjrvJ9Nu$mS3F)8{_ws2rInqpswW=W(zu9Ad5O)?MjcopR28Q@d^H ziey9f_oR;{yu+dT3l3)hn;mf#2@712Mz~Yc9rnZ=OSrqA-PzTiRa4dY;J1G%!Iraa z*)d<_!`Y57b7NdZm|EeGHyLK0z{IIY+xt=5L*ZiywXkQlY>_Lm_%=+WIU|Ok_s1Fa zJ(WI|uZVV8hv*5tITFXL<|Hiq{So5-@tyq8uPsSILhq5c mvV!Bj+1wZAeM1|#(B_eFX~qUFv^fx_&d?7WHh)#!Yso)X(Ug|} diff --git a/tests/spec_constant/test_convert.spv.dis b/tests/spec_constant/test_convert.spv.dis index 2895dabe..e1372feb 100644 --- a/tests/spec_constant/test_convert.spv.dis +++ b/tests/spec_constant/test_convert.spv.dis @@ -1,7 +1,7 @@ ; SPIR-V ; Version: 1.5 ; Generator: Google Shaderc over Glslang; 10 -; Bound: 49 +; Bound: 50 ; Schema: 0 OpCapability Shader OpCapability Float64 @@ -21,8 +21,7 @@ OpMemberName %SSBO_U_Sone 0 "val" OpMemberName %SSBO_U_Sone 1 "dummy" OpName %U_Sone "U_Sone" - OpName %DZERO "DZERO" - OpName %9999 "FZERO" + OpName %F_ONE "F_ONE" OpName %UONE "UONE" OpName %U_UONE "U_UONE" OpName %SSBO_U_Uone "SSBO_U_Uone" @@ -34,12 +33,14 @@ OpMemberName %SSBO_S_Sone 0 "val" OpMemberName %SSBO_S_Sone 1 "dummy" OpName %S_Sone "S_Sone" + OpName %D_ONE "D_ONE" + OpName %9999 "F_ONE2" OpName %S_UONE "S_UONE" OpName %SSBO_S_Uone "SSBO_S_Uone" OpMemberName %SSBO_S_Uone 0 "val" OpMemberName %SSBO_S_Uone 1 "dummy" OpName %S_Uone "S_Uone" - OpName %10000 "DZERO2" + OpName %10000 "D_ONE2" OpDecorate %SONE SpecId 0 OpDecorate %_arr_float_U_SONE ArrayStride 4 OpMemberDecorate %SSBO_U_Sone 0 Offset 0 @@ -47,7 +48,7 @@ OpDecorate %SSBO_U_Sone Block OpDecorate %U_Sone DescriptorSet 0 OpDecorate %U_Sone Binding 0 - OpDecorate %DZERO SpecId 2 + OpDecorate %F_ONE SpecId 2 OpDecorate %UONE SpecId 1 OpDecorate %_arr_float_U_UONE ArrayStride 4 OpMemberDecorate %SSBO_U_Uone 0 Offset 0 @@ -61,6 +62,7 @@ OpDecorate %SSBO_S_Sone Block OpDecorate %S_Sone DescriptorSet 0 OpDecorate %S_Sone Binding 2 + OpDecorate %D_ONE SpecId 3 OpDecorate %_arr_float_S_UONE ArrayStride 4 OpMemberDecorate %SSBO_S_Uone 0 Offset 0 OpMemberDecorate %SSBO_S_Uone 1 Offset 4 @@ -83,9 +85,7 @@ %_ptr_StorageBuffer_SSBO_U_Sone = OpTypePointer StorageBuffer %SSBO_U_Sone %U_Sone = OpVariable %_ptr_StorageBuffer_SSBO_U_Sone StorageBuffer %int_0 = OpConstant %int 0 - %double = OpTypeFloat 64 - %DZERO = OpSpecConstant %double 0 - %9999 = OpSpecConstantOp %float FConvert %DZERO + %F_ONE = OpSpecConstant %float 1 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float %ulong = OpTypeInt 64 0 %UONE = OpSpecConstant %ulong 1 @@ -99,8 +99,11 @@ %SSBO_S_Sone = OpTypeStruct %_arr_float_S_SONE %float %_ptr_StorageBuffer_SSBO_S_Sone = OpTypePointer StorageBuffer %SSBO_S_Sone %S_Sone = OpVariable %_ptr_StorageBuffer_SSBO_S_Sone StorageBuffer - %38 = OpSpecConstantOp %uint UConvert %UONE - %S_UONE = OpSpecConstantOp %int IAdd %38 %uint_0 + %double = OpTypeFloat 64 + %D_ONE = OpSpecConstant %double 1 + %9999 = OpSpecConstantOp %float FConvert %D_ONE + %39 = OpSpecConstantOp %uint UConvert %UONE + %S_UONE = OpSpecConstantOp %int IAdd %39 %uint_0 %_arr_float_S_UONE = OpTypeArray %float %S_UONE %SSBO_S_Uone = OpTypeStruct %_arr_float_S_UONE %float %_ptr_StorageBuffer_SSBO_S_Uone = OpTypePointer StorageBuffer %SSBO_S_Uone @@ -108,16 +111,16 @@ %v3uint = OpTypeVector %uint 3 %uint_1 = OpConstant %uint 1 %gl_WorkGroupSize = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1 - %10000 = OpSpecConstantOp %double FConvert %9999 + %10000 = OpSpecConstantOp %double FConvert %F_ONE %main = OpFunction %void None %3 %5 = OpLabel - %23 = OpAccessChain %_ptr_StorageBuffer_float %U_Sone %int_0 %int_0 - OpStore %23 %9999 - %31 = OpAccessChain %_ptr_StorageBuffer_float %U_Uone %int_0 %int_0 - OpStore %31 %9999 - %37 = OpAccessChain %_ptr_StorageBuffer_float %S_Sone %int_0 %int_0 - OpStore %37 %9999 - %44 = OpAccessChain %_ptr_StorageBuffer_float %S_Uone %int_0 %int_0 - OpStore %44 %9999 + %21 = OpAccessChain %_ptr_StorageBuffer_float %U_Sone %int_0 %int_0 + OpStore %21 %F_ONE + %29 = OpAccessChain %_ptr_StorageBuffer_float %U_Uone %int_0 %int_0 + OpStore %29 %F_ONE + %38 = OpAccessChain %_ptr_StorageBuffer_float %S_Sone %int_0 %int_0 + OpStore %38 %9999 + %45 = OpAccessChain %_ptr_StorageBuffer_float %S_Uone %int_0 %int_0 + OpStore %45 %9999 OpReturn OpFunctionEnd diff --git a/tests/spec_constant/test_convert.spv.dis.patch b/tests/spec_constant/test_convert.spv.dis.patch index bb954b1f..6d47e7c5 100644 --- a/tests/spec_constant/test_convert.spv.dis.patch +++ b/tests/spec_constant/test_convert.spv.dis.patch @@ -1,32 +1,24 @@ -25c25 -< OpName %FZERO "FZERO" +37c37 +< OpName %F_ONE2 "F_ONE2" --- -> OpName %9999 "FZERO" -42c42 -< OpName %DZERO2 "DZERO2" +> OpName %9999 "F_ONE2" +43c43 +< OpName %D_ONE2 "D_ONE2" --- -> OpName %10000 "DZERO2" -88c88 -< %FZERO = OpSpecConstantOp %float FConvert %DZERO +> OpName %10000 "D_ONE2" +104c104 +< %F_ONE2 = OpSpecConstantOp %float FConvert %D_ONE --- -> %9999 = OpSpecConstantOp %float FConvert %DZERO -111c111 -< %DZERO2 = OpSpecConstantOp %double FConvert %FZERO +> %9999 = OpSpecConstantOp %float FConvert %D_ONE +114c114 +< %D_ONE2 = OpSpecConstantOp %double FConvert %F_ONE --- -> %10000 = OpSpecConstantOp %double FConvert %9999 -115c115 -< OpStore %23 %FZERO +> %10000 = OpSpecConstantOp %double FConvert %F_ONE +122c122 +< OpStore %38 %F_ONE2 --- -> OpStore %23 %9999 -117c117 -< OpStore %31 %FZERO +> OpStore %38 %9999 +124c124 +< OpStore %45 %F_ONE2 --- -> OpStore %31 %9999 -119c119 -< OpStore %37 %FZERO ---- -> OpStore %37 %9999 -121c121 -< OpStore %44 %FZERO ---- -> OpStore %44 %9999 +> OpStore %45 %9999 diff --git a/tests/spec_constant/test_localsizeid.spv b/tests/spec_constant/test_localsizeid.spv index 98c9333d0f54f96c07238674d5a89aef71de333a..808b026999d4b9df645de58684b120ed121d091a 100644 GIT binary patch literal 11776 zcmZvi2b5LS6^5V842UR*fW3fdjKLTSmc*!xG7b|TGjSd-YK$2POmGs41x!rQi7`fv zF}?T1^xk_jz4zXG@4XoFedpZ`o3l8qz4re9v(NtbJ@?%E?yN=MjHR<$1G}|aty!(v zI>!9gjF#b?*39CE+nx5YS8iQ@?DCV2bAE2CPgmyVwT@^F5YNCit)1E|?`%INKNFjU z?T*dH_Q2*~dt!TGbFq2Y-q?I>A8Y}(5L<-pi|vQ)j~##=h#iC-j2(gk&V}{U#c+FKcx-IAJv6cIvdbo}+#Sj}oW(yMjjs zSFY^k544UZ=yc8+n;02fzn*v|HRT*vt=$Oj<#@l=Z`-u#YP`DMgJubMpmjHJXLM+I zB55r%r_((PS8|Rqr)YJyJ&0H>IY(%TYc22fNN-8ezPosJw~Z@xkHz=uuHLqh*t&9# zs4K4PdVWTFOG@2)fV(S4?uRRNJ&dJpcjeSo#MUhblsM{&>$;xFW=W}YJh-a!Kn%v3t|mp(W=CEpe^o*>9GVy357mL#uH``y_FxJ3hII*lUn;L|t)R*XOCz zTT<$tEM7gf{oI@)E_GLLiE|_8h`QpsuFq(vx1`iP72HjA@9DgCyF2R2Iijw(uIqE( zEGc#G1#Wj%Z9gNYflJ+X=h8SMa*n7guIu_PX_l0__Xdxrx~GFn-SHiDB0sK^%CXbtXRQt|j)q$vL8~xUTCvkGd|QN?&UQeq`vpQq$t4=E%_Hgr%mO zBWj9w!*)FDedQhM63?v<^T;R#8TNTLzE^W}(xUb$=ZKo(oon`&ck)PY303-99;|MA zO{wY2t<>yp+)7w#$~mH@c;}jZz%`Vw>?zq4HGx@CJ9SDIY-nJ*Y)PZbvI6y zdaI0wd;N_N_v&rf-k+Q!>WS-m{`PcPVt@BB9`5ybE^$+Ddw+6{s3)%L`8(F#(Cg2G z-f8yFhriV8?AX8ZLV%BY;<}!{i7v6fQR8O+{BddOZSSxA;J`;cab3^f*G{v4_cdll}J5u3sA49Yp8p17{(?|!G*zcs||vGHNJvwH)rPmAby}FyXco@BQIY-nL*LD5QY4?^;r>}K?u1MwZx^~XxYBfpPVD=iR*fP7rMlHe#^9*ckDXiQmROP_L%s43pLW?%UR?y$r@FJ*qscz4J(;wk(&gYAyQF!%_(>t{6h$OiW{*l$(m z2O4}-gZ+MT{X_7^{n#q9j>bEd_S|;P8gk|hb3e=rO|=fk9M%*sDX542ZgqWcZGY>b z#98y0CO2!!)tYjlX|1d&R?{{1;D%?7_*Tst@x3Y+*CiJk?pf9ls}b{?h_gm~w`Ps_ zcFh`cQN#6FL##$0=5-v8_nKxkcr!k0o(OhiO*z+OO}WstR@M}&8TV%kan?8q?8q8& zwT4`1_->#A?Jjyo@+&oC0=a4Y^uFE;MEnXAQ9$)^+bLZ(^^@v+XynBWuXj8gilG zH*eMus}c9ZAFq5Je&0H>hFq;77aDVjvxZm=_sr|K5}!3r2RpKcT&*D&8ha9F4Y3;T znHs&{wcZ(Uug-*bWDU7mLoPJ-BF-9OHQX~bw&C-241yh5L$2143yrzNSwp-8bI;W1 z{SCR}I?jf7WDU7mLoPJt5oZmt8t$1I55wo{7y>)8hFq;77aDsLXAQ9$?wJ}7$7hXU zup?{8)f#f4F`qbVh}Ce<)VLa-HAcXWtRYux$c4r}#92eEhI^*QBk)<{T(Bc+$kiHh zp|OBCYlziw&(wG%K5MK7JF+o6QBCsQC$kiHhp>Ys#))1@Vo~iLzeAc)a?8q8&wT4`1__spV z5Ub&ysc}6%YfOM0SwpVYkPD4Nh_i-R4fjlq$KkWaTCgK)$kiHhq2b>YSwp-8bI;Vc z0iQM2fgM>xuGWwXjl+nuhFA^vOpV9mv&JOYku~IM4Y|-*Oq?~uYPe@=+=$N_8^DgN zAy;e2g@*OAhFEjY)Ns!A@ttyMgK=eks=?+gpz2NdC4AZ5j5pqw_zC#M*dprP(!}PU z(BLD8Gd>b*f6KW#^Ph-KW9B($om=sXF~_n7KdA@HI_IB^O=GTiPCfa%VCq?4{1j{& zGvB$$JBm2^Fz>F|G-keYq5D+g0W9i0jrcmueCG~E_aS)q!MQ`hN8^KA41PM;Zx8v? z8r;`#>bMWjz#L+0J+mP9p}+MkV%N*ZzTS=ae|O$_XY}=K@H8gxegwaa*nYhxbK<(5 zLu?O`_grH0%y-V~dMI8^=e(|C@WI*F^T75c?{$g$8!qbJ9eh2ez83uRiPdvH^fnT! z=bU=S;)7G~1z`2$)f0PfRMjfM?dZxQ{O)j`L^Ui?M0!1k5@6*^IZJ7i0EwB0f0#c?no;dHWI1YB;ac zy34VfvCt3xrEu=6^P#teSUu;|I|(10dM^X3C$FB^cY<8hJ(<`Vp%>SC8{CYP_j2NC z%zWp(-plZ=bx!?L@WHA73b0!8>WgPLT-?`F!M<~R?mRPbj+YY0e&0&`O3dpw-#PU! z$E)w0`uD^Kr~a$J>dUJy-lO3{|J7jYF2g*p!QYGcqnLe}6Memgcn%hMuO)W9`Oewb z6?pq{&c05=2WMZe1KXFpeTl6p7j<7xysN(M4SzdkU*<$#Zy=t5#riiAyWV`~?CVOr zeK}`er{jaOuQ!41LEgRsM_;$VzZsjx)PEAToF`TOE!Z`f^Y$S3R?HqeuRbTipF#W) z%r)l3nR^>?KNfj!C!WU4cg}0riuW3v^BT^?2j?}s18l$YUW0hAhKs#I z6WfdPxtE87?ZtU}8O8@^FP=wr3r6F6j)8?)f~eIr{?FtYRaoAUes`*d0+7Bv0C%ozq}7 zomcaG{4^$~=GX9Q%Bv|ppyB+@^4wm4y$bVs;u^nBte$gO?=fI&JFnh__~6w023S3L z^~47@oY#0O@%=HMNuNzE_-_*XEIa>H%=frhJ?GTB2p^n!-vX;Aub%jzhKsu22D@e% z_8ctu2N3)2u?KVF8{#{}GqK3~F0t#)ch0^Zi?=W5?CWBDaQ5{*uzktfm-yg@i@Fa4 z`%bI(;rnpYnDa|9^{&UO=bU;I_~6w00a!hG^~8rXocGy%zXbavX5F~f9}?%kvwj5j zS}(zVh^hTJyxPvGy%ryw+CK)XEw8rt(1!C`-$nc&%yZ=V^-RS%`w6k<%=s5#=BRlC zUQOrKT!#-%&7XqRlvh)HSi^mLs8 z$ByGKUibP^?D!_0B0ib>e-nNN=C~RAC+JuBLGI79@W00TuxB)O21xFiSmgYMSe=|B zmvep#9;kBUa?bC-GpiiAob!9|tSUz?=llV@dzB-XbN&dPUFFE-oIip0sB+|T&Y!_^ zsvNnT^B1u9D({b6&iN~NuPR3_=ll&kx5|;rIe!Pwt8(OW&Og9=S2=Py=bzyDRgPTF z`4@PfDn~Bo{2RQW%8|=C{{b(oa^!N(f5D5Y9J!ox2YBBqM=t0554>NMBbRgT1n*zv z$mJaW_&%V@k;^%|fe);5|sV&%5u<#hw{Q&T94Dsnu%DYW;`* zIu^8Mv~=dQW|n!d-Dw|x)sBhdSDt)=>+@PYPGxO=YelP%dsaP)-_FiU$?dD>h`#E&ub=Bs_ma~0IQ81GHdE<)cjj*2wL7QC?W^aAzUsQK&&p8u zlG68h^w{d53z$mZdoY*2W2?99BDb%eBl@cAzCM4=C8duKaA$a6a6Fy)iF%23lG-!x z>|yCSf~BrmKIhFPg>_GL=`%XHmE1k+Iiioc?&Ei*)4inhS*b32UNbttljY}ovfkQ} z-OtG>>cU#PJ)RRiN3hg2%kN~Tdr9egFZ5XId#da99oy4a&k=pqbzi^d%_XJpz0vK? zn%&RIY3S0o-MKuT6Fo=tRo8v}?PxA3eNRV^roLyOOW)Bwef1pCS6%nr53jkT^u15f zYxORYto;-T0_wLzSeuIa)m(ZoBbzf@6+UrVB zAF|SOY-$H-=~*5;^607FyJt`NP4^P}`GYvt9w`0JA#eIkl9qmYj_9YZ`z^p5o0=^B z2F(Y%`&&ca?YDXN{`4HtPhI!(Z_OB&xW6Iu!S4RfC2#ue-k+W$`l;)F{@ohe+}+=K z^_?H_%Jm-&*tL{D#fTcb&sv_!;XtqMy3%=ik##bAJ9o z>NMwfzIo}l=lt{>(NA6XTa4Ff&d&$1)12R^dAHy0{pmTPpSten-}z2+ejW1m$Y^<9 z*6G`?z5Pnka=&_x=%=px`Oe@aeow~C`-jV8+lO-jy4!Q(wh402P|p!P)qD5sE$<-h z?j@z~h19f%N6L2WyB^)`yKVapa{KBzqOZE{>w8VRdkI~7TK7l0U3*?cUV8SIt(Km8 zj_9f0yJt^%Px2D`J%DwNlf1WeF?s1Xa%JhIc0@0A-D?RR<)zmH$=5fZ%_Zce*ZMu5 zjh-X=sq22eyLpLw8z=V&z1I!orQdKlzOp|(NA%l3UiVvy=Oy;rNZxLKV|}+N{o3W{ zu=LY&L_c-i&v!~M@w_&fr{7qgmu}B(yMJT#9MMy~chBC|GQ4*8lCn>~9G!tSd0*=? z^YWdUoFXmz)N@2n_1-;u$~$j|OWfyX*4K@W4S0?Ea^`dT+Z~NT^a^ILpV8=}8tuEH z>qj@buhG7nT0gVVTbjI=c@2bk4?Pm?2+wQutQ+L>ur8RgmJ<${>LZHk>Iad_3r4(? zW=6c1W`ect97fjz_GgB=y7~9A*Bi?5-Bi?EAedz^b zHhE^KWyEv0lH5JY_CB{WXXYtrM`r5P_oWxieaJIYEz`a-u4r=a)93h9W=Ce|)eOC0 z>`R^*Y8i1K-S@FQ&-Q7oIWj}9X6OZD4tZv%Wq5|(2S3q!oz)p=M`q~N4836NN1hpK z8J?MptC;iWaVFZ48G1ECFBo&lGea%IGn3K%+qvhgR^dA`V->n)=mldQd1k0(cxEzo zGUxj^8|}ypy_%sngRsYZ=H-MVv<%Noy^A?BR-+x6p;t5Xg0Vk&W~gO&W-=bioEhh! z9hsq5GxUPtyLD!$Wq4*X9>$y*YtW9&(5o4G!8m|CGt@FXLmB?Ri_AC|?Z^zhnxPkr zh2)u`mf@MncsO%rw9$^t(5o4G!B|9|8EP4xnT$s;XT~tvkr{e5LoXPmg>LoLHIlkq6#%os&GGDELs=mo=f`pi(v@XTaf!<-rG(2mT| zs~LL1IG8*$)G|CX8P_sr#sz3cX6V%nyBF=xibXh&w~)eOC0EFsSfb!I#Uof(&) z9hsq5GxUPtzaKI~of+4oGh+kVkr^A%HA62LOUW}sEyK^=vwAFZW?YJPWQJbN(3?Tn z!+&QiCmf+=_}Qy(V9tyQv?DY0YKC4gmXT+MT85v!j2oFV<1(}(GxTbPUNG#J8EV7N zUWRL4AMYuf8_iVKFK@Ip3+ehe<|BC1y@}a;G5O<}mk|fj?+HzA{Yi~pL7w$dX!p00 zyR-g@#57@@Yxa2(^D@G5Y@?stmE}6upF&I%UhkSb{i6wa_E$fZm?o@uE$Z$<9{aHF zuEaE9y=%dJ8oBSl(eLTx*Adpcwgm1LX3xR3rRcjchqny<4D^14{^^bGX*@Ze!!rqo z+Fs8p%5&&#-AwNF`mv8^lTQ;X2=71qW60f~_h60tdl0kNy5|0lWe(5&&q3Q?-~Fk3 z8!!4EhrXV$Z$6*rqP>@>dmg!b>s^!oU}pKQ$-g^uc=Df*mai{g?V0OE-{Z+|AcAk- zDYSiEv+q5a!?W)T(Du-`uX<+V#q)Ur`hR!aafh5Ike^80Ncb$e7N5^8%_d;Tt zu--NIvz6KXxaNLNVh+#!ya?@n^xcnoR^!F<=J(s@*M8fW?WbqIdoqV-zZawJr*A*? zY@*BPK36Nz|4sLIGTQxnf3C%Szl406a6Rs4JGp$<=^7ZAb?Wq@iPba^fsQItNn~~~XMK0fZ*W_QxEZ;Tx zXE28+|J7(&`tm~u-_P|m#55uQ$;3*&N&2rPt|43x?{$smGwlAYyASbU!g|-^`F}lm zFA;TbAfG0zcg_7@#q9oFbN^>Dhv)v^h<2~~?q5B(@fLA9Zz8w9^I3%Vm(S7ty_xX) zv663&`YnX#Wxda>>+WR-vwLyfy{uvm&%L}A?OycVi+UcR7klU@_q<{c!F(H@OxNYb z_hl!!OxI zb(w3J!;|@5v`l@O>H``tm_ulv)tdP}JejU%=GADKuFE`^IXs!~N6XZgsb1K4!8{M` z^L#R4?|6njKrYku%zQXnrt31>%;CxWAX=urO!Xo{FPLk|eeP@Khwx;&o|%t8%XD4l zFmre^Z%5l-U#9xN#tY^M+TV+s>2HZl*Yh* zP0jo$o=n#>^HFG-uFD){4o~LC&@%O9st;zKon`3ba4eVOWm8!wn+=vNRm^OJZoUC;MC00e+IZgMlgRH+ct(CVjqpE9ejVZZ z(+GdtAI)rU*W_Kq9G<+-q2=kzQyVydGeV=)O~?mzV)ujSIc)z z{>9AU$^Rl+zP^0*lE#a^4@CQX)%W`)ylKMqBMEtrVV38byi1tFllNt`JbiiU!yC`f z)AJoCK0(+w?)59=@$PHQR|)UKTGwP>&n(+D*&CR{ll?WcY<=14rG%dM>a(a!Ei)7Qy;o?Or0na84Kx-Rol=I~^G18skOnd&aUEIX{kh2I07g_y_7c%>8^0H#2{i=pmlj#F;3)XAx2J zJ#sm@MlaWVAKh2g=;fLppl4P!db#F@=vh^bUat8OdUjQ#mur5E-lwY3%QZhi?_1UA z<(i+O=TtR%x#nkRKdXE`db#H3=($ymUat8CdR|qdmur5Bo?q4I<(gli_pfU7a?P*N z3#uBuT=N_B0acA&uK6u`VO67-Ykr4bRMqI^n%|=jtZMXf%^%Q OpExecutionModeId %main LocalSizeId %249 %uint_1 %uint_1 -370d369 +> OpExecutionModeId %main LocalSizeId %262 %uint_1 %uint_1 +371d370 < OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize -587,589c586,587 -< %249 = OpSpecConstant %uint 1 +425c424 +< %SREM = OpSpecConstantOp %int SMod %STWO %SNEG_THREE +--- +> %SREM = OpSpecConstantOp %int SRem %STWO %SNEG_THREE +601,603c600,601 +< %262 = OpSpecConstant %uint 1 < %v3uint = OpTypeVector %uint 3 -< %gl_WorkGroupSize = OpSpecConstantComposite %v3uint %249 %uint_1 %uint_1 +< %gl_WorkGroupSize = OpSpecConstantComposite %v3uint %262 %uint_1 %uint_1 --- > ; default value should be respected, even if no compiler write things other than 1 -> %249 = OpSpecConstant %uint 4 +> %262 = OpSpecConstant %uint 4 diff --git a/tests/spec_constant/test_orig.glsl b/tests/spec_constant/test_orig.glsl index 265c890b..c24698fa 100644 --- a/tests/spec_constant/test_orig.glsl +++ b/tests/spec_constant/test_orig.glsl @@ -12,25 +12,24 @@ layout(constant_id = 6) const uint UTWO = 2; layout(constant_id = 7) const int SNEG_THREE = -3; const uint IADD = SONE + STWO + UONE + UTWO; // 6 -const uint ISUB = UTWO - SONE; // 1 +const uint ISUB = UTWO - SNEG_TWO; // 4 const uint IMUL = UTWO * UTWO; // 4 const uint UDIV = UTWO / UTWO; // 1 -const int SDIV = STWO / SNEG_TWO; // -1 -//const int SREM = STWO % SNEG_THREE; // 1 -const int SREM = 1; +const int SDIV = STWO / SNEG_THREE; // 0 +const int SREM = STWO % SNEG_THREE; // 2, instruction changed in patch... const int SMOD = STWO % SNEG_THREE; // -1 const uint UMOD = IADD % IMUL; // 2 -const uint LSHL = IADD << ISUB; // 12 -const uint RSHL = IADD >> ISUB; // 3 -const int RSHA = (-int(IADD)) >> (-SDIV); // -3 +const uint LSHL = IADD << (ISUB - 3); // 12 +const uint RSHL = IADD >> (ISUB - 3); // 3 +const int RSHA = (-int(IADD)) >> (1-SDIV); // -3 -const bool IEQ = IADD == ISUB; // false -const bool INEQ = IADD != ISUB; // true -const bool ULT = IADD < ISUB; // false -const bool ULE = IADD <= ISUB; // false -const bool UGT = IADD > ISUB; // true -const bool UGE = IADD >= ISUB; // true +const bool IEQ = IADD == (ISUB - 3); // false +const bool INEQ = IADD != (ISUB - 3); // true +const bool ULT = IADD < (ISUB - 3); // false +const bool ULE = IADD <= (ISUB - 3); // false +const bool UGT = IADD > (ISUB - 3); // true +const bool UGE = IADD >= (ISUB - 3); // true const bool SLT = SMOD < SREM; // true const bool SLE = SMOD <= SREM; // true @@ -42,25 +41,25 @@ const bool LAND = IEQ && SLT; // false const bool LNOT = !LOR; // false const uint AND = IADD & IADD; // 6 -const uint OR = IADD | ISUB; // 7 +const uint OR = IADD | (ISUB - 3); // 7 const uint XOR = IADD ^ IADD; // 0 const uint NOT = ~XOR; // UINT_MAX const bool LEQ = LAND == LNOT; // true const bool LNEQ = LAND != LNOT; // false -const uint SEL = IEQ ? IADD : ISUB; // 1 +const uint SEL = IEQ ? IADD : (ISUB - 3); // 1 #define DUMMY_SSBO(name, bind, size) layout(std430, set = 0, binding = bind) buffer SSBO_##name { float val[size]; float dummy; } name // Normalize all sizes to 1 element so that the default offsets in glslang matches up with what we should be computing. // If we do it right, we should get no layout(offset = N) expressions. DUMMY_SSBO(IAdd, 0, IADD - 5); -DUMMY_SSBO(ISub, 1, ISUB); +DUMMY_SSBO(ISub, 1, ISUB - 3); DUMMY_SSBO(IMul, 2, IMUL - 3); DUMMY_SSBO(UDiv, 3, UDIV); -DUMMY_SSBO(SDiv, 4, SDIV + 2); -DUMMY_SSBO(SRem, 5, SREM); +DUMMY_SSBO(SDiv, 4, SDIV + 1); +DUMMY_SSBO(SRem, 5, SREM - 1); DUMMY_SSBO(SMod, 6, SMOD + 2); DUMMY_SSBO(UMod, 7, UMOD - 1); DUMMY_SSBO(LShl, 8, LSHL - 11); @@ -80,12 +79,12 @@ DUMMY_SSBO(Lor, 21, LOR ? 1 : 2); DUMMY_SSBO(Land, 22, LAND ? 2 : 1); DUMMY_SSBO(Lnot, 23, LNOT ? 2 : 1); DUMMY_SSBO(And, 24, AND - 5); -DUMMY_SSBO(Or, 24, OR - 6); -DUMMY_SSBO(Xor, 24, XOR + 1); -DUMMY_SSBO(Not, 25, NOT - 0xfffffffeu); -DUMMY_SSBO(Leq, 26, LEQ ? 1 : 2); -DUMMY_SSBO(Lneq, 27, LNEQ ? 2 : 1); -DUMMY_SSBO(Sel, 28, SEL); +DUMMY_SSBO(Or, 25, OR - 6); +DUMMY_SSBO(Xor, 26, XOR + 1); +DUMMY_SSBO(Not, 27, NOT - 0xfffffffeu); +DUMMY_SSBO(Leq, 28, LEQ ? 1 : 2); +DUMMY_SSBO(Lneq, 29, LNEQ ? 2 : 1); +DUMMY_SSBO(Sel, 30, SEL); void main() { diff --git a/tests/spec_constant/test_orig.spv.dis b/tests/spec_constant/test_orig.spv.dis index 118b8b07..97255a44 100644 --- a/tests/spec_constant/test_orig.spv.dis +++ b/tests/spec_constant/test_orig.spv.dis @@ -1,7 +1,7 @@ ; SPIR-V ; Version: 1.5 ; Generator: Google Shaderc over Glslang; 10 -; Bound: 254 +; Bound: 267 ; Schema: 0 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -21,6 +21,7 @@ OpMemberName %SSBO_IAdd 0 "val" OpMemberName %SSBO_IAdd 1 "dummy" OpName %IAdd "IAdd" + OpName %SNEG_TWO "SNEG_TWO" OpName %ISUB "ISUB" OpName %SSBO_ISub "SSBO_ISub" OpMemberName %SSBO_ISub 0 "val" @@ -36,17 +37,17 @@ OpMemberName %SSBO_UDiv 0 "val" OpMemberName %SSBO_UDiv 1 "dummy" OpName %UDiv "UDiv" - OpName %SNEG_TWO "SNEG_TWO" + OpName %SNEG_THREE "SNEG_THREE" OpName %SDIV "SDIV" OpName %SSBO_SDiv "SSBO_SDiv" OpMemberName %SSBO_SDiv 0 "val" OpMemberName %SSBO_SDiv 1 "dummy" OpName %SDiv "SDiv" + OpName %SREM "SREM" OpName %SSBO_SRem "SSBO_SRem" OpMemberName %SSBO_SRem 0 "val" OpMemberName %SSBO_SRem 1 "dummy" OpName %SRem "SRem" - OpName %SNEG_THREE "SNEG_THREE" OpName %SMOD "SMOD" OpName %SSBO_SMod "SSBO_SMod" OpMemberName %SSBO_SMod 0 "val" @@ -184,13 +185,14 @@ OpDecorate %SSBO_IAdd Block OpDecorate %IAdd DescriptorSet 0 OpDecorate %IAdd Binding 0 - OpDecorate %_arr_float_ISUB ArrayStride 4 + OpDecorate %SNEG_TWO SpecId 4 + OpDecorate %_arr_float_32 ArrayStride 4 OpMemberDecorate %SSBO_ISub 0 Offset 0 OpMemberDecorate %SSBO_ISub 1 Offset 4 OpDecorate %SSBO_ISub Block OpDecorate %ISub DescriptorSet 0 OpDecorate %ISub Binding 1 - OpDecorate %_arr_float_37 ArrayStride 4 + OpDecorate %_arr_float_39 ArrayStride 4 OpMemberDecorate %SSBO_IMul 0 Offset 0 OpMemberDecorate %SSBO_IMul 1 Offset 4 OpDecorate %SSBO_IMul Block @@ -202,171 +204,170 @@ OpDecorate %SSBO_UDiv Block OpDecorate %UDiv DescriptorSet 0 OpDecorate %UDiv Binding 3 - OpDecorate %SNEG_TWO SpecId 4 - OpDecorate %_arr_float_52 ArrayStride 4 + OpDecorate %SNEG_THREE SpecId 7 + OpDecorate %_arr_float_54 ArrayStride 4 OpMemberDecorate %SSBO_SDiv 0 Offset 0 OpMemberDecorate %SSBO_SDiv 1 Offset 4 OpDecorate %SSBO_SDiv Block OpDecorate %SDiv DescriptorSet 0 OpDecorate %SDiv Binding 4 - OpDecorate %_arr_float_uint_1 ArrayStride 4 + OpDecorate %_arr_float_61 ArrayStride 4 OpMemberDecorate %SSBO_SRem 0 Offset 0 OpMemberDecorate %SSBO_SRem 1 Offset 4 OpDecorate %SSBO_SRem Block OpDecorate %SRem DescriptorSet 0 OpDecorate %SRem Binding 5 - OpDecorate %SNEG_THREE SpecId 7 - OpDecorate %_arr_float_66 ArrayStride 4 + OpDecorate %_arr_float_69 ArrayStride 4 OpMemberDecorate %SSBO_SMod 0 Offset 0 OpMemberDecorate %SSBO_SMod 1 Offset 4 OpDecorate %SSBO_SMod Block OpDecorate %SMod DescriptorSet 0 OpDecorate %SMod Binding 6 - OpDecorate %_arr_float_73 ArrayStride 4 + OpDecorate %_arr_float_77 ArrayStride 4 OpMemberDecorate %SSBO_UMod 0 Offset 0 OpMemberDecorate %SSBO_UMod 1 Offset 4 OpDecorate %SSBO_UMod Block OpDecorate %UMod DescriptorSet 0 OpDecorate %UMod Binding 7 - OpDecorate %_arr_float_81 ArrayStride 4 + OpDecorate %_arr_float_86 ArrayStride 4 OpMemberDecorate %SSBO_LShl 0 Offset 0 OpMemberDecorate %SSBO_LShl 1 Offset 4 OpDecorate %SSBO_LShl Block OpDecorate %LShl DescriptorSet 0 OpDecorate %LShl Binding 8 - OpDecorate %_arr_float_89 ArrayStride 4 + OpDecorate %_arr_float_95 ArrayStride 4 OpMemberDecorate %SSBO_RShl 0 Offset 0 OpMemberDecorate %SSBO_RShl 1 Offset 4 OpDecorate %SSBO_RShl Block OpDecorate %RShl DescriptorSet 0 OpDecorate %RShl Binding 9 - OpDecorate %_arr_float_100 ArrayStride 4 + OpDecorate %_arr_float_106 ArrayStride 4 OpMemberDecorate %SSBO_RSha 0 Offset 0 OpMemberDecorate %SSBO_RSha 1 Offset 4 OpDecorate %SSBO_RSha Block OpDecorate %RSha DescriptorSet 0 OpDecorate %RSha Binding 10 - OpDecorate %_arr_float_109 ArrayStride 4 + OpDecorate %_arr_float_115 ArrayStride 4 OpMemberDecorate %SSBO_IEq 0 Offset 0 OpMemberDecorate %SSBO_IEq 1 Offset 4 OpDecorate %SSBO_IEq Block OpDecorate %IEq DescriptorSet 0 OpDecorate %IEq Binding 11 - OpDecorate %_arr_float_116 ArrayStride 4 + OpDecorate %_arr_float_123 ArrayStride 4 OpMemberDecorate %SSBO_INeq 0 Offset 0 OpMemberDecorate %SSBO_INeq 1 Offset 4 OpDecorate %SSBO_INeq Block OpDecorate %INeq DescriptorSet 0 OpDecorate %INeq Binding 12 - OpDecorate %_arr_float_123 ArrayStride 4 + OpDecorate %_arr_float_131 ArrayStride 4 OpMemberDecorate %SSBO_Ult 0 Offset 0 OpMemberDecorate %SSBO_Ult 1 Offset 4 OpDecorate %SSBO_Ult Block OpDecorate %Ult DescriptorSet 0 OpDecorate %Ult Binding 13 - OpDecorate %_arr_float_130 ArrayStride 4 + OpDecorate %_arr_float_139 ArrayStride 4 OpMemberDecorate %SSBO_Ule 0 Offset 0 OpMemberDecorate %SSBO_Ule 1 Offset 4 OpDecorate %SSBO_Ule Block OpDecorate %Ule DescriptorSet 0 OpDecorate %Ule Binding 14 - OpDecorate %_arr_float_137 ArrayStride 4 + OpDecorate %_arr_float_147 ArrayStride 4 OpMemberDecorate %SSBO_Ugt 0 Offset 0 OpMemberDecorate %SSBO_Ugt 1 Offset 4 OpDecorate %SSBO_Ugt Block OpDecorate %Ugt DescriptorSet 0 OpDecorate %Ugt Binding 15 - OpDecorate %_arr_float_144 ArrayStride 4 + OpDecorate %_arr_float_155 ArrayStride 4 OpMemberDecorate %SSBO_Uge 0 Offset 0 OpMemberDecorate %SSBO_Uge 1 Offset 4 OpDecorate %SSBO_Uge Block OpDecorate %Uge DescriptorSet 0 OpDecorate %Uge Binding 16 - OpDecorate %_arr_float_151 ArrayStride 4 + OpDecorate %_arr_float_162 ArrayStride 4 OpMemberDecorate %SSBO_Slt 0 Offset 0 OpMemberDecorate %SSBO_Slt 1 Offset 4 OpDecorate %SSBO_Slt Block OpDecorate %Slt DescriptorSet 0 OpDecorate %Slt Binding 17 - OpDecorate %_arr_float_158 ArrayStride 4 + OpDecorate %_arr_float_169 ArrayStride 4 OpMemberDecorate %SSBO_Sle 0 Offset 0 OpMemberDecorate %SSBO_Sle 1 Offset 4 OpDecorate %SSBO_Sle Block OpDecorate %Sle DescriptorSet 0 OpDecorate %Sle Binding 18 - OpDecorate %_arr_float_165 ArrayStride 4 + OpDecorate %_arr_float_176 ArrayStride 4 OpMemberDecorate %SSBO_Sgt 0 Offset 0 OpMemberDecorate %SSBO_Sgt 1 Offset 4 OpDecorate %SSBO_Sgt Block OpDecorate %Sgt DescriptorSet 0 OpDecorate %Sgt Binding 19 - OpDecorate %_arr_float_172 ArrayStride 4 + OpDecorate %_arr_float_183 ArrayStride 4 OpMemberDecorate %SSBO_Sge 0 Offset 0 OpMemberDecorate %SSBO_Sge 1 Offset 4 OpDecorate %SSBO_Sge Block OpDecorate %Sge DescriptorSet 0 OpDecorate %Sge Binding 20 - OpDecorate %_arr_float_179 ArrayStride 4 + OpDecorate %_arr_float_190 ArrayStride 4 OpMemberDecorate %SSBO_Lor 0 Offset 0 OpMemberDecorate %SSBO_Lor 1 Offset 4 OpDecorate %SSBO_Lor Block OpDecorate %Lor DescriptorSet 0 OpDecorate %Lor Binding 21 - OpDecorate %_arr_float_186 ArrayStride 4 + OpDecorate %_arr_float_197 ArrayStride 4 OpMemberDecorate %SSBO_Land 0 Offset 0 OpMemberDecorate %SSBO_Land 1 Offset 4 OpDecorate %SSBO_Land Block OpDecorate %Land DescriptorSet 0 OpDecorate %Land Binding 22 - OpDecorate %_arr_float_193 ArrayStride 4 + OpDecorate %_arr_float_204 ArrayStride 4 OpMemberDecorate %SSBO_Lnot 0 Offset 0 OpMemberDecorate %SSBO_Lnot 1 Offset 4 OpDecorate %SSBO_Lnot Block OpDecorate %Lnot DescriptorSet 0 OpDecorate %Lnot Binding 23 - OpDecorate %_arr_float_200 ArrayStride 4 + OpDecorate %_arr_float_211 ArrayStride 4 OpMemberDecorate %SSBO_And 0 Offset 0 OpMemberDecorate %SSBO_And 1 Offset 4 OpDecorate %SSBO_And Block OpDecorate %And DescriptorSet 0 OpDecorate %And Binding 24 - OpDecorate %_arr_float_208 ArrayStride 4 + OpDecorate %_arr_float_220 ArrayStride 4 OpMemberDecorate %SSBO_Or 0 Offset 0 OpMemberDecorate %SSBO_Or 1 Offset 4 OpDecorate %SSBO_Or Block OpDecorate %Or DescriptorSet 0 - OpDecorate %Or Binding 24 - OpDecorate %_arr_float_215 ArrayStride 4 + OpDecorate %Or Binding 25 + OpDecorate %_arr_float_227 ArrayStride 4 OpMemberDecorate %SSBO_Xor 0 Offset 0 OpMemberDecorate %SSBO_Xor 1 Offset 4 OpDecorate %SSBO_Xor Block OpDecorate %Xor DescriptorSet 0 - OpDecorate %Xor Binding 24 - OpDecorate %_arr_float_223 ArrayStride 4 + OpDecorate %Xor Binding 26 + OpDecorate %_arr_float_235 ArrayStride 4 OpMemberDecorate %SSBO_Not 0 Offset 0 OpMemberDecorate %SSBO_Not 1 Offset 4 OpDecorate %SSBO_Not Block OpDecorate %Not DescriptorSet 0 - OpDecorate %Not Binding 25 - OpDecorate %_arr_float_230 ArrayStride 4 + OpDecorate %Not Binding 27 + OpDecorate %_arr_float_242 ArrayStride 4 OpMemberDecorate %SSBO_Leq 0 Offset 0 OpMemberDecorate %SSBO_Leq 1 Offset 4 OpDecorate %SSBO_Leq Block OpDecorate %Leq DescriptorSet 0 - OpDecorate %Leq Binding 26 - OpDecorate %_arr_float_237 ArrayStride 4 + OpDecorate %Leq Binding 28 + OpDecorate %_arr_float_249 ArrayStride 4 OpMemberDecorate %SSBO_Lneq 0 Offset 0 OpMemberDecorate %SSBO_Lneq 1 Offset 4 OpDecorate %SSBO_Lneq Block OpDecorate %Lneq DescriptorSet 0 - OpDecorate %Lneq Binding 27 + OpDecorate %Lneq Binding 29 OpDecorate %_arr_float_SEL ArrayStride 4 OpMemberDecorate %SSBO_Sel 0 Offset 0 OpMemberDecorate %SSBO_Sel 1 Offset 4 OpDecorate %SSBO_Sel Block OpDecorate %Sel DescriptorSet 0 - OpDecorate %Sel Binding 28 - OpDecorate %249 SpecId 8 + OpDecorate %Sel Binding 30 + OpDecorate %262 SpecId 8 OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize OpDecorate %TRUE SpecId 0 OpDecorate %FALSE SpecId 1 @@ -393,17 +394,19 @@ %int_0 = OpConstant %int 0 %float_0 = OpConstant %float 0 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float - %28 = OpSpecConstantOp %uint IAdd %SONE %uint_0 - %ISUB = OpSpecConstantOp %uint ISub %UTWO %28 -%_arr_float_ISUB = OpTypeArray %float %ISUB - %SSBO_ISub = OpTypeStruct %_arr_float_ISUB %float + %SNEG_TWO = OpSpecConstant %int -2 + %29 = OpSpecConstantOp %uint IAdd %SNEG_TWO %uint_0 + %ISUB = OpSpecConstantOp %uint ISub %UTWO %29 + %uint_3 = OpConstant %uint 3 + %32 = OpSpecConstantOp %uint ISub %ISUB %uint_3 +%_arr_float_32 = OpTypeArray %float %32 + %SSBO_ISub = OpTypeStruct %_arr_float_32 %float %_ptr_StorageBuffer_SSBO_ISub = OpTypePointer StorageBuffer %SSBO_ISub %ISub = OpVariable %_ptr_StorageBuffer_SSBO_ISub StorageBuffer %IMUL = OpSpecConstantOp %uint IMul %UTWO %UTWO - %uint_3 = OpConstant %uint 3 - %37 = OpSpecConstantOp %uint ISub %IMUL %uint_3 -%_arr_float_37 = OpTypeArray %float %37 - %SSBO_IMul = OpTypeStruct %_arr_float_37 %float + %39 = OpSpecConstantOp %uint ISub %IMUL %uint_3 +%_arr_float_39 = OpTypeArray %float %39 + %SSBO_IMul = OpTypeStruct %_arr_float_39 %float %_ptr_StorageBuffer_SSBO_IMul = OpTypePointer StorageBuffer %SSBO_IMul %IMul = OpVariable %_ptr_StorageBuffer_SSBO_IMul StorageBuffer %UDIV = OpSpecConstantOp %uint UDiv %UTWO %UTWO @@ -411,247 +414,258 @@ %SSBO_UDiv = OpTypeStruct %_arr_float_UDIV %float %_ptr_StorageBuffer_SSBO_UDiv = OpTypePointer StorageBuffer %SSBO_UDiv %UDiv = OpVariable %_ptr_StorageBuffer_SSBO_UDiv StorageBuffer - %SNEG_TWO = OpSpecConstant %int -2 - %SDIV = OpSpecConstantOp %int SDiv %STWO %SNEG_TWO - %int_2 = OpConstant %int 2 - %52 = OpSpecConstantOp %int IAdd %SDIV %int_2 -%_arr_float_52 = OpTypeArray %float %52 - %SSBO_SDiv = OpTypeStruct %_arr_float_52 %float + %SNEG_THREE = OpSpecConstant %int -3 + %SDIV = OpSpecConstantOp %int SDiv %STWO %SNEG_THREE + %int_1 = OpConstant %int 1 + %54 = OpSpecConstantOp %int IAdd %SDIV %int_1 +%_arr_float_54 = OpTypeArray %float %54 + %SSBO_SDiv = OpTypeStruct %_arr_float_54 %float %_ptr_StorageBuffer_SSBO_SDiv = OpTypePointer StorageBuffer %SSBO_SDiv %SDiv = OpVariable %_ptr_StorageBuffer_SSBO_SDiv StorageBuffer - %uint_1 = OpConstant %uint 1 -%_arr_float_uint_1 = OpTypeArray %float %uint_1 - %SSBO_SRem = OpTypeStruct %_arr_float_uint_1 %float + %SREM = OpSpecConstantOp %int SMod %STWO %SNEG_THREE + %61 = OpSpecConstantOp %int ISub %SREM %int_1 +%_arr_float_61 = OpTypeArray %float %61 + %SSBO_SRem = OpTypeStruct %_arr_float_61 %float %_ptr_StorageBuffer_SSBO_SRem = OpTypePointer StorageBuffer %SSBO_SRem %SRem = OpVariable %_ptr_StorageBuffer_SSBO_SRem StorageBuffer - %SNEG_THREE = OpSpecConstant %int -3 %SMOD = OpSpecConstantOp %int SMod %STWO %SNEG_THREE - %66 = OpSpecConstantOp %int IAdd %SMOD %int_2 -%_arr_float_66 = OpTypeArray %float %66 - %SSBO_SMod = OpTypeStruct %_arr_float_66 %float + %int_2 = OpConstant %int 2 + %69 = OpSpecConstantOp %int IAdd %SMOD %int_2 +%_arr_float_69 = OpTypeArray %float %69 + %SSBO_SMod = OpTypeStruct %_arr_float_69 %float %_ptr_StorageBuffer_SSBO_SMod = OpTypePointer StorageBuffer %SSBO_SMod %SMod = OpVariable %_ptr_StorageBuffer_SSBO_SMod StorageBuffer %UMOD = OpSpecConstantOp %uint UMod %IADD %IMUL - %73 = OpSpecConstantOp %uint ISub %UMOD %uint_1 -%_arr_float_73 = OpTypeArray %float %73 - %SSBO_UMod = OpTypeStruct %_arr_float_73 %float + %uint_1 = OpConstant %uint 1 + %77 = OpSpecConstantOp %uint ISub %UMOD %uint_1 +%_arr_float_77 = OpTypeArray %float %77 + %SSBO_UMod = OpTypeStruct %_arr_float_77 %float %_ptr_StorageBuffer_SSBO_UMod = OpTypePointer StorageBuffer %SSBO_UMod %UMod = OpVariable %_ptr_StorageBuffer_SSBO_UMod StorageBuffer - %LSHL = OpSpecConstantOp %uint ShiftLeftLogical %IADD %ISUB + %83 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %LSHL = OpSpecConstantOp %uint ShiftLeftLogical %IADD %83 %uint_11 = OpConstant %uint 11 - %81 = OpSpecConstantOp %uint ISub %LSHL %uint_11 -%_arr_float_81 = OpTypeArray %float %81 - %SSBO_LShl = OpTypeStruct %_arr_float_81 %float + %86 = OpSpecConstantOp %uint ISub %LSHL %uint_11 +%_arr_float_86 = OpTypeArray %float %86 + %SSBO_LShl = OpTypeStruct %_arr_float_86 %float %_ptr_StorageBuffer_SSBO_LShl = OpTypePointer StorageBuffer %SSBO_LShl %LShl = OpVariable %_ptr_StorageBuffer_SSBO_LShl StorageBuffer - %RSHL = OpSpecConstantOp %uint ShiftRightLogical %IADD %ISUB + %92 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %RSHL = OpSpecConstantOp %uint ShiftRightLogical %IADD %92 %uint_2 = OpConstant %uint 2 - %89 = OpSpecConstantOp %uint ISub %RSHL %uint_2 -%_arr_float_89 = OpTypeArray %float %89 - %SSBO_RShl = OpTypeStruct %_arr_float_89 %float + %95 = OpSpecConstantOp %uint ISub %RSHL %uint_2 +%_arr_float_95 = OpTypeArray %float %95 + %SSBO_RShl = OpTypeStruct %_arr_float_95 %float %_ptr_StorageBuffer_SSBO_RShl = OpTypePointer StorageBuffer %SSBO_RShl %RShl = OpVariable %_ptr_StorageBuffer_SSBO_RShl StorageBuffer - %95 = OpSpecConstantOp %int IAdd %IADD %uint_0 - %96 = OpSpecConstantOp %int SNegate %95 - %97 = OpSpecConstantOp %int SNegate %SDIV - %RSHA = OpSpecConstantOp %int ShiftRightArithmetic %96 %97 + %101 = OpSpecConstantOp %int IAdd %IADD %uint_0 + %102 = OpSpecConstantOp %int SNegate %101 + %103 = OpSpecConstantOp %int ISub %int_1 %SDIV + %RSHA = OpSpecConstantOp %int ShiftRightArithmetic %102 %103 %int_4 = OpConstant %int 4 - %100 = OpSpecConstantOp %int IAdd %RSHA %int_4 -%_arr_float_100 = OpTypeArray %float %100 - %SSBO_RSha = OpTypeStruct %_arr_float_100 %float + %106 = OpSpecConstantOp %int IAdd %RSHA %int_4 +%_arr_float_106 = OpTypeArray %float %106 + %SSBO_RSha = OpTypeStruct %_arr_float_106 %float %_ptr_StorageBuffer_SSBO_RSha = OpTypePointer StorageBuffer %SSBO_RSha %RSha = OpVariable %_ptr_StorageBuffer_SSBO_RSha StorageBuffer + %112 = OpSpecConstantOp %uint ISub %ISUB %uint_3 %bool = OpTypeBool - %IEQ = OpSpecConstantOp %bool IEqual %IADD %ISUB - %int_1 = OpConstant %int 1 - %109 = OpSpecConstantOp %int Select %IEQ %int_2 %int_1 -%_arr_float_109 = OpTypeArray %float %109 - %SSBO_IEq = OpTypeStruct %_arr_float_109 %float + %IEQ = OpSpecConstantOp %bool IEqual %IADD %112 + %115 = OpSpecConstantOp %int Select %IEQ %int_2 %int_1 +%_arr_float_115 = OpTypeArray %float %115 + %SSBO_IEq = OpTypeStruct %_arr_float_115 %float %_ptr_StorageBuffer_SSBO_IEq = OpTypePointer StorageBuffer %SSBO_IEq %IEq = OpVariable %_ptr_StorageBuffer_SSBO_IEq StorageBuffer - %INEQ = OpSpecConstantOp %bool INotEqual %IADD %ISUB - %116 = OpSpecConstantOp %int Select %INEQ %int_1 %int_2 -%_arr_float_116 = OpTypeArray %float %116 - %SSBO_INeq = OpTypeStruct %_arr_float_116 %float + %121 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %INEQ = OpSpecConstantOp %bool INotEqual %IADD %121 + %123 = OpSpecConstantOp %int Select %INEQ %int_1 %int_2 +%_arr_float_123 = OpTypeArray %float %123 + %SSBO_INeq = OpTypeStruct %_arr_float_123 %float %_ptr_StorageBuffer_SSBO_INeq = OpTypePointer StorageBuffer %SSBO_INeq %INeq = OpVariable %_ptr_StorageBuffer_SSBO_INeq StorageBuffer - %ULT = OpSpecConstantOp %bool ULessThan %IADD %ISUB - %123 = OpSpecConstantOp %int Select %ULT %int_2 %int_1 -%_arr_float_123 = OpTypeArray %float %123 - %SSBO_Ult = OpTypeStruct %_arr_float_123 %float + %129 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %ULT = OpSpecConstantOp %bool ULessThan %IADD %129 + %131 = OpSpecConstantOp %int Select %ULT %int_2 %int_1 +%_arr_float_131 = OpTypeArray %float %131 + %SSBO_Ult = OpTypeStruct %_arr_float_131 %float %_ptr_StorageBuffer_SSBO_Ult = OpTypePointer StorageBuffer %SSBO_Ult %Ult = OpVariable %_ptr_StorageBuffer_SSBO_Ult StorageBuffer - %ULE = OpSpecConstantOp %bool ULessThanEqual %IADD %ISUB - %130 = OpSpecConstantOp %int Select %ULE %int_2 %int_1 -%_arr_float_130 = OpTypeArray %float %130 - %SSBO_Ule = OpTypeStruct %_arr_float_130 %float + %137 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %ULE = OpSpecConstantOp %bool ULessThanEqual %IADD %137 + %139 = OpSpecConstantOp %int Select %ULE %int_2 %int_1 +%_arr_float_139 = OpTypeArray %float %139 + %SSBO_Ule = OpTypeStruct %_arr_float_139 %float %_ptr_StorageBuffer_SSBO_Ule = OpTypePointer StorageBuffer %SSBO_Ule %Ule = OpVariable %_ptr_StorageBuffer_SSBO_Ule StorageBuffer - %UGT = OpSpecConstantOp %bool UGreaterThan %IADD %ISUB - %137 = OpSpecConstantOp %int Select %UGT %int_1 %int_2 -%_arr_float_137 = OpTypeArray %float %137 - %SSBO_Ugt = OpTypeStruct %_arr_float_137 %float + %145 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %UGT = OpSpecConstantOp %bool UGreaterThan %IADD %145 + %147 = OpSpecConstantOp %int Select %UGT %int_1 %int_2 +%_arr_float_147 = OpTypeArray %float %147 + %SSBO_Ugt = OpTypeStruct %_arr_float_147 %float %_ptr_StorageBuffer_SSBO_Ugt = OpTypePointer StorageBuffer %SSBO_Ugt %Ugt = OpVariable %_ptr_StorageBuffer_SSBO_Ugt StorageBuffer - %UGE = OpSpecConstantOp %bool UGreaterThanEqual %IADD %ISUB - %144 = OpSpecConstantOp %int Select %UGE %int_1 %int_2 -%_arr_float_144 = OpTypeArray %float %144 - %SSBO_Uge = OpTypeStruct %_arr_float_144 %float + %153 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %UGE = OpSpecConstantOp %bool UGreaterThanEqual %IADD %153 + %155 = OpSpecConstantOp %int Select %UGE %int_1 %int_2 +%_arr_float_155 = OpTypeArray %float %155 + %SSBO_Uge = OpTypeStruct %_arr_float_155 %float %_ptr_StorageBuffer_SSBO_Uge = OpTypePointer StorageBuffer %SSBO_Uge %Uge = OpVariable %_ptr_StorageBuffer_SSBO_Uge StorageBuffer - %SLT = OpSpecConstantOp %bool SLessThan %SMOD %int_1 - %151 = OpSpecConstantOp %int Select %SLT %int_1 %int_2 -%_arr_float_151 = OpTypeArray %float %151 - %SSBO_Slt = OpTypeStruct %_arr_float_151 %float + %SLT = OpSpecConstantOp %bool SLessThan %SMOD %SREM + %162 = OpSpecConstantOp %int Select %SLT %int_1 %int_2 +%_arr_float_162 = OpTypeArray %float %162 + %SSBO_Slt = OpTypeStruct %_arr_float_162 %float %_ptr_StorageBuffer_SSBO_Slt = OpTypePointer StorageBuffer %SSBO_Slt %Slt = OpVariable %_ptr_StorageBuffer_SSBO_Slt StorageBuffer - %SLE = OpSpecConstantOp %bool SLessThanEqual %SMOD %int_1 - %158 = OpSpecConstantOp %int Select %SLE %int_1 %int_2 -%_arr_float_158 = OpTypeArray %float %158 - %SSBO_Sle = OpTypeStruct %_arr_float_158 %float + %SLE = OpSpecConstantOp %bool SLessThanEqual %SMOD %SREM + %169 = OpSpecConstantOp %int Select %SLE %int_1 %int_2 +%_arr_float_169 = OpTypeArray %float %169 + %SSBO_Sle = OpTypeStruct %_arr_float_169 %float %_ptr_StorageBuffer_SSBO_Sle = OpTypePointer StorageBuffer %SSBO_Sle %Sle = OpVariable %_ptr_StorageBuffer_SSBO_Sle StorageBuffer - %SGT = OpSpecConstantOp %bool SGreaterThan %SMOD %int_1 - %165 = OpSpecConstantOp %int Select %SGT %int_2 %int_1 -%_arr_float_165 = OpTypeArray %float %165 - %SSBO_Sgt = OpTypeStruct %_arr_float_165 %float + %SGT = OpSpecConstantOp %bool SGreaterThan %SMOD %SREM + %176 = OpSpecConstantOp %int Select %SGT %int_2 %int_1 +%_arr_float_176 = OpTypeArray %float %176 + %SSBO_Sgt = OpTypeStruct %_arr_float_176 %float %_ptr_StorageBuffer_SSBO_Sgt = OpTypePointer StorageBuffer %SSBO_Sgt %Sgt = OpVariable %_ptr_StorageBuffer_SSBO_Sgt StorageBuffer - %SGE = OpSpecConstantOp %bool SGreaterThanEqual %SMOD %int_1 - %172 = OpSpecConstantOp %int Select %SGE %int_2 %int_1 -%_arr_float_172 = OpTypeArray %float %172 - %SSBO_Sge = OpTypeStruct %_arr_float_172 %float + %SGE = OpSpecConstantOp %bool SGreaterThanEqual %SMOD %SREM + %183 = OpSpecConstantOp %int Select %SGE %int_2 %int_1 +%_arr_float_183 = OpTypeArray %float %183 + %SSBO_Sge = OpTypeStruct %_arr_float_183 %float %_ptr_StorageBuffer_SSBO_Sge = OpTypePointer StorageBuffer %SSBO_Sge %Sge = OpVariable %_ptr_StorageBuffer_SSBO_Sge StorageBuffer %LOR = OpSpecConstantOp %bool LogicalOr %IEQ %SLT - %179 = OpSpecConstantOp %int Select %LOR %int_1 %int_2 -%_arr_float_179 = OpTypeArray %float %179 - %SSBO_Lor = OpTypeStruct %_arr_float_179 %float + %190 = OpSpecConstantOp %int Select %LOR %int_1 %int_2 +%_arr_float_190 = OpTypeArray %float %190 + %SSBO_Lor = OpTypeStruct %_arr_float_190 %float %_ptr_StorageBuffer_SSBO_Lor = OpTypePointer StorageBuffer %SSBO_Lor %Lor = OpVariable %_ptr_StorageBuffer_SSBO_Lor StorageBuffer %LAND = OpSpecConstantOp %bool LogicalAnd %IEQ %SLT - %186 = OpSpecConstantOp %int Select %LAND %int_2 %int_1 -%_arr_float_186 = OpTypeArray %float %186 - %SSBO_Land = OpTypeStruct %_arr_float_186 %float + %197 = OpSpecConstantOp %int Select %LAND %int_2 %int_1 +%_arr_float_197 = OpTypeArray %float %197 + %SSBO_Land = OpTypeStruct %_arr_float_197 %float %_ptr_StorageBuffer_SSBO_Land = OpTypePointer StorageBuffer %SSBO_Land %Land = OpVariable %_ptr_StorageBuffer_SSBO_Land StorageBuffer %LNOT = OpSpecConstantOp %bool LogicalNot %LOR - %193 = OpSpecConstantOp %int Select %LNOT %int_2 %int_1 -%_arr_float_193 = OpTypeArray %float %193 - %SSBO_Lnot = OpTypeStruct %_arr_float_193 %float + %204 = OpSpecConstantOp %int Select %LNOT %int_2 %int_1 +%_arr_float_204 = OpTypeArray %float %204 + %SSBO_Lnot = OpTypeStruct %_arr_float_204 %float %_ptr_StorageBuffer_SSBO_Lnot = OpTypePointer StorageBuffer %SSBO_Lnot %Lnot = OpVariable %_ptr_StorageBuffer_SSBO_Lnot StorageBuffer %AND = OpSpecConstantOp %uint BitwiseAnd %IADD %IADD - %200 = OpSpecConstantOp %uint ISub %AND %uint_5 -%_arr_float_200 = OpTypeArray %float %200 - %SSBO_And = OpTypeStruct %_arr_float_200 %float + %211 = OpSpecConstantOp %uint ISub %AND %uint_5 +%_arr_float_211 = OpTypeArray %float %211 + %SSBO_And = OpTypeStruct %_arr_float_211 %float %_ptr_StorageBuffer_SSBO_And = OpTypePointer StorageBuffer %SSBO_And %And = OpVariable %_ptr_StorageBuffer_SSBO_And StorageBuffer - %OR = OpSpecConstantOp %uint BitwiseOr %IADD %ISUB + %217 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %OR = OpSpecConstantOp %uint BitwiseOr %IADD %217 %uint_6 = OpConstant %uint 6 - %208 = OpSpecConstantOp %uint ISub %OR %uint_6 -%_arr_float_208 = OpTypeArray %float %208 - %SSBO_Or = OpTypeStruct %_arr_float_208 %float + %220 = OpSpecConstantOp %uint ISub %OR %uint_6 +%_arr_float_220 = OpTypeArray %float %220 + %SSBO_Or = OpTypeStruct %_arr_float_220 %float %_ptr_StorageBuffer_SSBO_Or = OpTypePointer StorageBuffer %SSBO_Or %Or = OpVariable %_ptr_StorageBuffer_SSBO_Or StorageBuffer %XOR = OpSpecConstantOp %uint BitwiseXor %IADD %IADD - %215 = OpSpecConstantOp %uint IAdd %XOR %uint_1 -%_arr_float_215 = OpTypeArray %float %215 - %SSBO_Xor = OpTypeStruct %_arr_float_215 %float + %227 = OpSpecConstantOp %uint IAdd %XOR %uint_1 +%_arr_float_227 = OpTypeArray %float %227 + %SSBO_Xor = OpTypeStruct %_arr_float_227 %float %_ptr_StorageBuffer_SSBO_Xor = OpTypePointer StorageBuffer %SSBO_Xor %Xor = OpVariable %_ptr_StorageBuffer_SSBO_Xor StorageBuffer %NOT = OpSpecConstantOp %uint Not %XOR %uint_4294967294 = OpConstant %uint 4294967294 - %223 = OpSpecConstantOp %uint ISub %NOT %uint_4294967294 -%_arr_float_223 = OpTypeArray %float %223 - %SSBO_Not = OpTypeStruct %_arr_float_223 %float + %235 = OpSpecConstantOp %uint ISub %NOT %uint_4294967294 +%_arr_float_235 = OpTypeArray %float %235 + %SSBO_Not = OpTypeStruct %_arr_float_235 %float %_ptr_StorageBuffer_SSBO_Not = OpTypePointer StorageBuffer %SSBO_Not %Not = OpVariable %_ptr_StorageBuffer_SSBO_Not StorageBuffer %LEQ = OpSpecConstantOp %bool LogicalEqual %LAND %LNOT - %230 = OpSpecConstantOp %int Select %LEQ %int_1 %int_2 -%_arr_float_230 = OpTypeArray %float %230 - %SSBO_Leq = OpTypeStruct %_arr_float_230 %float + %242 = OpSpecConstantOp %int Select %LEQ %int_1 %int_2 +%_arr_float_242 = OpTypeArray %float %242 + %SSBO_Leq = OpTypeStruct %_arr_float_242 %float %_ptr_StorageBuffer_SSBO_Leq = OpTypePointer StorageBuffer %SSBO_Leq %Leq = OpVariable %_ptr_StorageBuffer_SSBO_Leq StorageBuffer %LNEQ = OpSpecConstantOp %bool LogicalNotEqual %LAND %LNOT - %237 = OpSpecConstantOp %int Select %LNEQ %int_2 %int_1 -%_arr_float_237 = OpTypeArray %float %237 - %SSBO_Lneq = OpTypeStruct %_arr_float_237 %float + %249 = OpSpecConstantOp %int Select %LNEQ %int_2 %int_1 +%_arr_float_249 = OpTypeArray %float %249 + %SSBO_Lneq = OpTypeStruct %_arr_float_249 %float %_ptr_StorageBuffer_SSBO_Lneq = OpTypePointer StorageBuffer %SSBO_Lneq %Lneq = OpVariable %_ptr_StorageBuffer_SSBO_Lneq StorageBuffer - %SEL = OpSpecConstantOp %uint Select %IEQ %IADD %ISUB + %255 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %SEL = OpSpecConstantOp %uint Select %IEQ %IADD %255 %_arr_float_SEL = OpTypeArray %float %SEL %SSBO_Sel = OpTypeStruct %_arr_float_SEL %float %_ptr_StorageBuffer_SSBO_Sel = OpTypePointer StorageBuffer %SSBO_Sel %Sel = OpVariable %_ptr_StorageBuffer_SSBO_Sel StorageBuffer - %249 = OpSpecConstant %uint 1 + %262 = OpSpecConstant %uint 1 %v3uint = OpTypeVector %uint 3 -%gl_WorkGroupSize = OpSpecConstantComposite %v3uint %249 %uint_1 %uint_1 +%gl_WorkGroupSize = OpSpecConstantComposite %v3uint %262 %uint_1 %uint_1 %TRUE = OpSpecConstantTrue %bool %FALSE = OpSpecConstantFalse %bool %main = OpFunction %void None %3 %5 = OpLabel %27 = OpAccessChain %_ptr_StorageBuffer_float %IAdd %int_0 %int_0 OpStore %27 %float_0 - %34 = OpAccessChain %_ptr_StorageBuffer_float %ISub %int_0 %int_0 - OpStore %34 %float_0 - %42 = OpAccessChain %_ptr_StorageBuffer_float %IMul %int_0 %int_0 - OpStore %42 %float_0 - %48 = OpAccessChain %_ptr_StorageBuffer_float %UDiv %int_0 %int_0 - OpStore %48 %float_0 - %57 = OpAccessChain %_ptr_StorageBuffer_float %SDiv %int_0 %int_0 - OpStore %57 %float_0 - %63 = OpAccessChain %_ptr_StorageBuffer_float %SRem %int_0 %int_0 - OpStore %63 %float_0 - %71 = OpAccessChain %_ptr_StorageBuffer_float %SMod %int_0 %int_0 - OpStore %71 %float_0 - %78 = OpAccessChain %_ptr_StorageBuffer_float %UMod %int_0 %int_0 - OpStore %78 %float_0 - %86 = OpAccessChain %_ptr_StorageBuffer_float %LShl %int_0 %int_0 - OpStore %86 %float_0 - %94 = OpAccessChain %_ptr_StorageBuffer_float %RShl %int_0 %int_0 - OpStore %94 %float_0 - %105 = OpAccessChain %_ptr_StorageBuffer_float %RSha %int_0 %int_0 - OpStore %105 %float_0 - %114 = OpAccessChain %_ptr_StorageBuffer_float %IEq %int_0 %int_0 - OpStore %114 %float_0 - %121 = OpAccessChain %_ptr_StorageBuffer_float %INeq %int_0 %int_0 - OpStore %121 %float_0 - %128 = OpAccessChain %_ptr_StorageBuffer_float %Ult %int_0 %int_0 + %37 = OpAccessChain %_ptr_StorageBuffer_float %ISub %int_0 %int_0 + OpStore %37 %float_0 + %44 = OpAccessChain %_ptr_StorageBuffer_float %IMul %int_0 %int_0 + OpStore %44 %float_0 + %50 = OpAccessChain %_ptr_StorageBuffer_float %UDiv %int_0 %int_0 + OpStore %50 %float_0 + %59 = OpAccessChain %_ptr_StorageBuffer_float %SDiv %int_0 %int_0 + OpStore %59 %float_0 + %66 = OpAccessChain %_ptr_StorageBuffer_float %SRem %int_0 %int_0 + OpStore %66 %float_0 + %74 = OpAccessChain %_ptr_StorageBuffer_float %SMod %int_0 %int_0 + OpStore %74 %float_0 + %82 = OpAccessChain %_ptr_StorageBuffer_float %UMod %int_0 %int_0 + OpStore %82 %float_0 + %91 = OpAccessChain %_ptr_StorageBuffer_float %LShl %int_0 %int_0 + OpStore %91 %float_0 + %100 = OpAccessChain %_ptr_StorageBuffer_float %RShl %int_0 %int_0 + OpStore %100 %float_0 + %111 = OpAccessChain %_ptr_StorageBuffer_float %RSha %int_0 %int_0 + OpStore %111 %float_0 + %120 = OpAccessChain %_ptr_StorageBuffer_float %IEq %int_0 %int_0 + OpStore %120 %float_0 + %128 = OpAccessChain %_ptr_StorageBuffer_float %INeq %int_0 %int_0 OpStore %128 %float_0 - %135 = OpAccessChain %_ptr_StorageBuffer_float %Ule %int_0 %int_0 - OpStore %135 %float_0 - %142 = OpAccessChain %_ptr_StorageBuffer_float %Ugt %int_0 %int_0 - OpStore %142 %float_0 - %149 = OpAccessChain %_ptr_StorageBuffer_float %Uge %int_0 %int_0 - OpStore %149 %float_0 - %156 = OpAccessChain %_ptr_StorageBuffer_float %Slt %int_0 %int_0 - OpStore %156 %float_0 - %163 = OpAccessChain %_ptr_StorageBuffer_float %Sle %int_0 %int_0 - OpStore %163 %float_0 - %170 = OpAccessChain %_ptr_StorageBuffer_float %Sgt %int_0 %int_0 - OpStore %170 %float_0 - %177 = OpAccessChain %_ptr_StorageBuffer_float %Sge %int_0 %int_0 - OpStore %177 %float_0 - %184 = OpAccessChain %_ptr_StorageBuffer_float %Lor %int_0 %int_0 - OpStore %184 %float_0 - %191 = OpAccessChain %_ptr_StorageBuffer_float %Land %int_0 %int_0 - OpStore %191 %float_0 - %198 = OpAccessChain %_ptr_StorageBuffer_float %Lnot %int_0 %int_0 - OpStore %198 %float_0 - %205 = OpAccessChain %_ptr_StorageBuffer_float %And %int_0 %int_0 - OpStore %205 %float_0 - %213 = OpAccessChain %_ptr_StorageBuffer_float %Or %int_0 %int_0 - OpStore %213 %float_0 - %220 = OpAccessChain %_ptr_StorageBuffer_float %Xor %int_0 %int_0 - OpStore %220 %float_0 - %228 = OpAccessChain %_ptr_StorageBuffer_float %Not %int_0 %int_0 - OpStore %228 %float_0 - %235 = OpAccessChain %_ptr_StorageBuffer_float %Leq %int_0 %int_0 - OpStore %235 %float_0 - %242 = OpAccessChain %_ptr_StorageBuffer_float %Lneq %int_0 %int_0 - OpStore %242 %float_0 - %248 = OpAccessChain %_ptr_StorageBuffer_float %Sel %int_0 %int_0 - OpStore %248 %float_0 + %136 = OpAccessChain %_ptr_StorageBuffer_float %Ult %int_0 %int_0 + OpStore %136 %float_0 + %144 = OpAccessChain %_ptr_StorageBuffer_float %Ule %int_0 %int_0 + OpStore %144 %float_0 + %152 = OpAccessChain %_ptr_StorageBuffer_float %Ugt %int_0 %int_0 + OpStore %152 %float_0 + %160 = OpAccessChain %_ptr_StorageBuffer_float %Uge %int_0 %int_0 + OpStore %160 %float_0 + %167 = OpAccessChain %_ptr_StorageBuffer_float %Slt %int_0 %int_0 + OpStore %167 %float_0 + %174 = OpAccessChain %_ptr_StorageBuffer_float %Sle %int_0 %int_0 + OpStore %174 %float_0 + %181 = OpAccessChain %_ptr_StorageBuffer_float %Sgt %int_0 %int_0 + OpStore %181 %float_0 + %188 = OpAccessChain %_ptr_StorageBuffer_float %Sge %int_0 %int_0 + OpStore %188 %float_0 + %195 = OpAccessChain %_ptr_StorageBuffer_float %Lor %int_0 %int_0 + OpStore %195 %float_0 + %202 = OpAccessChain %_ptr_StorageBuffer_float %Land %int_0 %int_0 + OpStore %202 %float_0 + %209 = OpAccessChain %_ptr_StorageBuffer_float %Lnot %int_0 %int_0 + OpStore %209 %float_0 + %216 = OpAccessChain %_ptr_StorageBuffer_float %And %int_0 %int_0 + OpStore %216 %float_0 + %225 = OpAccessChain %_ptr_StorageBuffer_float %Or %int_0 %int_0 + OpStore %225 %float_0 + %232 = OpAccessChain %_ptr_StorageBuffer_float %Xor %int_0 %int_0 + OpStore %232 %float_0 + %240 = OpAccessChain %_ptr_StorageBuffer_float %Not %int_0 %int_0 + OpStore %240 %float_0 + %247 = OpAccessChain %_ptr_StorageBuffer_float %Leq %int_0 %int_0 + OpStore %247 %float_0 + %254 = OpAccessChain %_ptr_StorageBuffer_float %Lneq %int_0 %int_0 + OpStore %254 %float_0 + %261 = OpAccessChain %_ptr_StorageBuffer_float %Sel %int_0 %int_0 + OpStore %261 %float_0 OpReturn OpFunctionEnd diff --git a/tests/test-spirv-reflect.cpp b/tests/test-spirv-reflect.cpp index 19a83768..3182ea9a 100644 --- a/tests/test-spirv-reflect.cpp +++ b/tests/test-spirv-reflect.cpp @@ -1231,10 +1231,186 @@ TEST_F(SpirvReflectMultiEntryPointTest, ChangeDescriptorSetNumber) { ASSERT_EQ(set0->bindings[0]->set, 1); } -TEST(SpirvReflectSpecializationConstantTest, TestSpecParsing) { +TEST(SpirvReflectSpecializationConstantTest, TestSpecParsing32) { std::vector spirv_; SpvReflectShaderModule module_; - const std::string spirv_path = "../tests/entry_exec_mode/comp_local_size.spv"; + const std::string spirv_path = "../tests/spec_constant/test_32bit.spv"; + std::ifstream spirv_file(spirv_path, std::ios::binary | std::ios::ate); + std::streampos spirv_file_nbytes = spirv_file.tellg(); + spirv_file.seekg(0); + spirv_.resize(spirv_file_nbytes); + spirv_file.read(reinterpret_cast(spirv_.data()), spirv_.size()); + + SpvReflectResult result = + spvReflectCreateShaderModule(spirv_.size(), spirv_.data(), &module_); + ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result) + << "spvReflectCreateShaderModule() failed"; + + EXPECT_EQ(module_.entry_point_count, 1); + EXPECT_EQ(module_.entry_points[0].shader_stage, SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT); + EXPECT_EQ(module_.entry_points[0].local_size.flags, 4); + ASSERT_EQ(module_.specialization_constant_count, 9); + for (uint32_t i = 0; i < 9; ++i) { + const SpvReflectSpecializationConstant* p_constant = &module_.specialization_constants[i]; + switch (p_constant->constant_id) { + default: + EXPECT_EQ(0, 1) << "Invalid constant id"; + case 0: + EXPECT_STREQ(p_constant->name, "TRUE"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_BOOL); + EXPECT_EQ(p_constant->default_value.value.uint32_bool_value, 1); + break; + case 1: + EXPECT_STREQ(p_constant->name, "FALSE"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_BOOL); + EXPECT_EQ(p_constant->default_value.value.uint32_bool_value, 0); + break; + case 2: + EXPECT_STREQ(p_constant->name, "SONE"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.signedness, 1); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.width, 32); + EXPECT_EQ(p_constant->default_value.value.sint32_value, 1); + break; + case 3: + EXPECT_STREQ(p_constant->name, "STWO"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.signedness, 1); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.width, 32); + EXPECT_EQ(p_constant->default_value.value.sint32_value, 2); + break; + case 4: + EXPECT_STREQ(p_constant->name, "SNEG_TWO"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.signedness, 1); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.width, 32); + EXPECT_EQ(p_constant->default_value.value.sint32_value, -2); + break; + case 5: + EXPECT_STREQ(p_constant->name, "UONE"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.signedness, 0); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.width, 32); + EXPECT_EQ(p_constant->default_value.value.sint32_value, 1); + break; + case 6: + EXPECT_STREQ(p_constant->name, "UTWO"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.signedness, 0); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.width, 32); + EXPECT_EQ(p_constant->default_value.value.sint32_value, 2); + break; + case 7: + EXPECT_STREQ(p_constant->name, "SNEG_THREE"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.signedness, 1); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.width, 32); + EXPECT_EQ(p_constant->default_value.value.sint32_value, -3); + break; + case 8: + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.signedness, 0); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.width, 32); + EXPECT_EQ(p_constant->default_value.value.sint32_value, 4); + break; + } + } + spvReflectDestroyShaderModule(&module_); +} + +TEST(SpirvReflectSpecializationConstantTest, TestSpecParsing64) +{ + std::vector spirv_; + SpvReflectShaderModule module_; + const std::string spirv_path = "../tests/spec_constant/test_64bit.spv"; + std::ifstream spirv_file(spirv_path, std::ios::binary | std::ios::ate); + std::streampos spirv_file_nbytes = spirv_file.tellg(); + spirv_file.seekg(0); + spirv_.resize(spirv_file_nbytes); + spirv_file.read(reinterpret_cast(spirv_.data()), spirv_.size()); + + SpvReflectResult result = + spvReflectCreateShaderModule(spirv_.size(), spirv_.data(), &module_); + ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result) + << "spvReflectCreateShaderModule() failed"; + + EXPECT_EQ(module_.entry_point_count, 1); + EXPECT_EQ(module_.entry_points[0].shader_stage, SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT); + EXPECT_EQ(module_.entry_points[0].local_size.flags, 4); + ASSERT_EQ(module_.specialization_constant_count, 9); + for (uint32_t i = 0; i < 9; ++i) { + const SpvReflectSpecializationConstant* p_constant = &module_.specialization_constants[i]; + switch (p_constant->constant_id) { + default: + EXPECT_EQ(0, 1) << "Invalid constant id"; + case 0: + EXPECT_STREQ(p_constant->name, "TRUE"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_BOOL); + EXPECT_EQ(p_constant->default_value.value.uint32_bool_value, 1); + break; + case 1: + EXPECT_STREQ(p_constant->name, "FALSE"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_BOOL); + EXPECT_EQ(p_constant->default_value.value.uint32_bool_value, 0); + break; + case 2: + EXPECT_STREQ(p_constant->name, "SONE"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.signedness, 1); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.width, 64); + EXPECT_EQ(p_constant->default_value.value.sint32_value, 1); + break; + case 3: + EXPECT_STREQ(p_constant->name, "STWO"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.signedness, 1); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.width, 64); + EXPECT_EQ(p_constant->default_value.value.sint32_value, 2); + break; + case 4: + EXPECT_STREQ(p_constant->name, "SNEG_TWO"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.signedness, 1); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.width, 64); + EXPECT_EQ(p_constant->default_value.value.sint32_value, -2); + break; + case 5: + EXPECT_STREQ(p_constant->name, "UONE"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.signedness, 0); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.width, 64); + EXPECT_EQ(p_constant->default_value.value.sint32_value, 1); + break; + case 6: + EXPECT_STREQ(p_constant->name, "UTWO"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.signedness, 0); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.width, 64); + EXPECT_EQ(p_constant->default_value.value.sint32_value, 2); + break; + case 7: + EXPECT_STREQ(p_constant->name, "SNEG_THREE"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.signedness, 1); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.width, 64); + EXPECT_EQ(p_constant->default_value.value.sint32_value, -3); + break; + case 8: + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.signedness, 0); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.width, 32); + EXPECT_EQ(p_constant->default_value.value.sint32_value, 4); + break; + } + } + spvReflectDestroyShaderModule(&module_); +} + +TEST(SpirvReflectSpecializationConstantTest, TestSpecParsingFloat) +{ + std::vector spirv_; + SpvReflectShaderModule module_; + const std::string spirv_path = "../tests/spec_constant/test_convert.spv"; std::ifstream spirv_file(spirv_path, std::ios::binary | std::ios::ate); std::streampos spirv_file_nbytes = spirv_file.tellg(); spirv_file.seekg(0); @@ -1248,10 +1424,235 @@ TEST(SpirvReflectSpecializationConstantTest, TestSpecParsing) { EXPECT_EQ(module_.entry_point_count, 1); EXPECT_EQ(module_.entry_points[0].shader_stage, SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT); - EXPECT_EQ(module_.entry_points[0].local_size.x, 1); - EXPECT_EQ(module_.entry_points[0].local_size.y, 1); - EXPECT_EQ(module_.entry_points[0].local_size.z, 1); + // glslc emits this builtin, even if no speconstant specified, flags!=0 + //EXPECT_EQ(module_.entry_points[0].local_size.flags, 0); + ASSERT_EQ(module_.specialization_constant_count, 4); + for (uint32_t i = 0; i < 4; ++i) { + const SpvReflectSpecializationConstant* p_constant = &module_.specialization_constants[i]; + switch (p_constant->constant_id) { + default: + EXPECT_EQ(0, 1) << "Invalid constant id"; + case 0: + EXPECT_STREQ(p_constant->name, "SONE"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.signedness, 1); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.width, 64); + EXPECT_EQ(p_constant->default_value.value.sint32_value, 1); + break; + case 1: + EXPECT_STREQ(p_constant->name, "UONE"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.signedness, 0); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.width, 64); + EXPECT_EQ(p_constant->default_value.value.sint32_value, 1); + break; + case 2: + EXPECT_STREQ(p_constant->name, "F_ONE"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_FLOAT); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.width, 32); + EXPECT_EQ(p_constant->default_value.value.float32_value, 1); + break; + case 3: + EXPECT_STREQ(p_constant->name, "D_ONE"); + EXPECT_EQ(p_constant->type->type_flags, SPV_REFLECT_TYPE_FLAG_FLOAT); + EXPECT_EQ(p_constant->type->traits.numeric.scalar.width, 64); + EXPECT_EQ(p_constant->default_value.value.float64_value, 1); + break; + } + } + spvReflectDestroyShaderModule(&module_); +} + +TEST(SpirvReflectSpecializationConstantTest, TestEvaluate32) +{ + std::vector spirv_; + SpvReflectShaderModule module_; + const std::string spirv_path = "../tests/spec_constant/test_32bit.spv"; + std::ifstream spirv_file(spirv_path, std::ios::binary | std::ios::ate); + std::streampos spirv_file_nbytes = spirv_file.tellg(); + spirv_file.seekg(0); + spirv_.resize(spirv_file_nbytes); + spirv_file.read(reinterpret_cast(spirv_.data()), spirv_.size()); + + SpvReflectResult result = + spvReflectCreateShaderModule2(SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT | SPV_REFLECT_MODULE_FLAG_NO_COPY, spirv_.size(), spirv_.data(), &module_); + ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result) + << "spvReflectCreateShaderModule() failed"; + + EXPECT_EQ(module_.entry_point_count, 1); + EXPECT_EQ(module_.entry_points[0].shader_stage, SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT); + EXPECT_EQ(module_.entry_points[0].local_size.flags, 4); + ASSERT_EQ(module_.specialization_constant_count, 9); + SpvReflectEvaluation* p_eval = spvReflectGetEvaluationInterface(&module_); + ASSERT_NE(p_eval, nullptr); + const SpvReflectValue* res = nullptr; + ASSERT_EQ(spvReflectEvaluateResult(p_eval, module_.entry_points[0].local_size.x, &res), SPV_REFLECT_RESULT_SUCCESS); + ASSERT_NE(res, nullptr); + ASSERT_EQ(res->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_VECTOR); + ASSERT_EQ(res->type->traits.numeric.vector.component_count, 3); + ASSERT_EQ(res->type->traits.numeric.scalar.width, 32); + ASSERT_EQ(res->type->traits.numeric.scalar.signedness, 0); + ASSERT_EQ(res->data.numeric.vector.value[0].value.uint32_bool_value, 4); + ASSERT_EQ(res->data.numeric.vector.value[1].value.uint32_bool_value, 1); + ASSERT_EQ(res->data.numeric.vector.value[2].value.uint32_bool_value, 1); + + ASSERT_EQ(module_.descriptor_binding_count, 31); + for (uint32_t i = 0; i < module_.descriptor_binding_count; ++i) { + ASSERT_NE(module_.descriptor_bindings[i].type_description, nullptr); + SpvReflectTypeDescription* p_type = module_.descriptor_bindings[i].type_description; + ASSERT_EQ(p_type->type_flags, SPV_REFLECT_TYPE_FLAG_STRUCT | SPV_REFLECT_TYPE_FLAG_EXTERNAL_BLOCK); + ASSERT_EQ(p_type->member_count, 2); + ASSERT_NE(p_type->members, nullptr); + SpvReflectTypeDescription* p_type_arr = &p_type->members[0]; + ASSERT_EQ(p_type_arr->type_flags, SPV_REFLECT_TYPE_FLAG_FLOAT| SPV_REFLECT_TYPE_FLAG_ARRAY); + ASSERT_EQ(p_type_arr->traits.array.dims_count, 1); + ASSERT_EQ(p_type_arr->traits.array.dims[0], 0xffffffff); + res = nullptr; + ASSERT_EQ(spvReflectEvaluateResult(p_eval, p_type_arr->traits.array.spec_constant_op_ids[0], &res), SPV_REFLECT_RESULT_SUCCESS); + ASSERT_NE(res, nullptr); + ASSERT_NE(res->type, nullptr); + ASSERT_EQ(res->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + ASSERT_EQ(res->type->traits.numeric.scalar.width, 32); + ASSERT_EQ(res->data.numeric.scalar.value.uint32_bool_value, 1); + } + + SpvReflectScalarValueData data = {0}; + data.value.sint32_value = -2; + ASSERT_EQ(spvReflectSetSpecConstantValue(p_eval, 7, SPIRV_REFLECT_SCALAR_TYPE_I32, &data), SPV_REFLECT_RESULT_SUCCESS); + SpvReflectTypeDescription* p_type = module_.descriptor_bindings[10].type_description; + SpvReflectTypeDescription* p_type_arr = &p_type->members[0]; + res = nullptr; + ASSERT_EQ(spvReflectEvaluateResult(p_eval, p_type_arr->traits.array.spec_constant_op_ids[0], &res), SPV_REFLECT_RESULT_SUCCESS); + ASSERT_NE(res, nullptr); + ASSERT_NE(res->type, nullptr); + ASSERT_EQ(res->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + ASSERT_EQ(res->type->traits.numeric.scalar.width, 32); + ASSERT_EQ(res->data.numeric.scalar.value.sint32_value, 2); + + spvReflectDestroyShaderModule(&module_); +} + +TEST(SpirvReflectSpecializationConstantTest, TestEvaluate64) +{ + std::vector spirv_; + SpvReflectShaderModule module_; + const std::string spirv_path = "../tests/spec_constant/test_64bit.spv"; + std::ifstream spirv_file(spirv_path, std::ios::binary | std::ios::ate); + std::streampos spirv_file_nbytes = spirv_file.tellg(); + spirv_file.seekg(0); + spirv_.resize(spirv_file_nbytes); + spirv_file.read(reinterpret_cast(spirv_.data()), spirv_.size()); + + SpvReflectResult result = + spvReflectCreateShaderModule2(SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT | SPV_REFLECT_MODULE_FLAG_NO_COPY, spirv_.size(), spirv_.data(), &module_); + ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result) + << "spvReflectCreateShaderModule() failed"; + + EXPECT_EQ(module_.entry_point_count, 1); + EXPECT_EQ(module_.entry_points[0].shader_stage, SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT); EXPECT_EQ(module_.entry_points[0].local_size.flags, 4); + ASSERT_EQ(module_.specialization_constant_count, 9); + SpvReflectEvaluation* p_eval = spvReflectGetEvaluationInterface(&module_); + ASSERT_NE(p_eval, nullptr); + const SpvReflectValue* res = nullptr; + ASSERT_EQ(spvReflectEvaluateResult(p_eval, module_.entry_points[0].local_size.x, &res), SPV_REFLECT_RESULT_SUCCESS); + ASSERT_NE(res, nullptr); + ASSERT_EQ(res->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_VECTOR); + ASSERT_EQ(res->type->traits.numeric.vector.component_count, 3); + ASSERT_EQ(res->type->traits.numeric.scalar.width, 32); + ASSERT_EQ(res->type->traits.numeric.scalar.signedness, 0); + ASSERT_EQ(res->data.numeric.vector.value[0].value.uint32_bool_value, 4); + ASSERT_EQ(res->data.numeric.vector.value[1].value.uint32_bool_value, 1); + ASSERT_EQ(res->data.numeric.vector.value[2].value.uint32_bool_value, 1); + + ASSERT_EQ(module_.descriptor_binding_count, 31); + for (uint32_t i = 0; i < module_.descriptor_binding_count; ++i) { + ASSERT_NE(module_.descriptor_bindings[i].type_description, nullptr); + SpvReflectTypeDescription* p_type = module_.descriptor_bindings[i].type_description; + ASSERT_EQ(p_type->type_flags, SPV_REFLECT_TYPE_FLAG_STRUCT | SPV_REFLECT_TYPE_FLAG_EXTERNAL_BLOCK); + ASSERT_EQ(p_type->member_count, 2); + ASSERT_NE(p_type->members, nullptr); + SpvReflectTypeDescription* p_type_arr = &p_type->members[0]; + ASSERT_EQ(p_type_arr->type_flags, SPV_REFLECT_TYPE_FLAG_FLOAT | SPV_REFLECT_TYPE_FLAG_ARRAY); + ASSERT_EQ(p_type_arr->traits.array.dims_count, 1); + ASSERT_EQ(p_type_arr->traits.array.dims[0], 0xffffffff); + const SpvReflectValue* res = nullptr; + ASSERT_EQ(spvReflectEvaluateResult(p_eval, p_type_arr->traits.array.spec_constant_op_ids[0], &res), SPV_REFLECT_RESULT_SUCCESS); + ASSERT_NE(res, nullptr); + ASSERT_NE(res->type, nullptr); + ASSERT_EQ(res->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + ASSERT_EQ(res->type->traits.numeric.scalar.width, 64); + ASSERT_EQ(res->data.numeric.scalar.value.uint64_value, 1); + } + SpvReflectScalarValueData data = {0}; + data.value.sint64_value = -2; + ASSERT_EQ(spvReflectSetSpecConstantValue(p_eval, 7, SPIRV_REFLECT_SCALAR_TYPE_I64, &data), SPV_REFLECT_RESULT_SUCCESS); + SpvReflectTypeDescription* p_type = module_.descriptor_bindings[10].type_description; + SpvReflectTypeDescription* p_type_arr = &p_type->members[0]; + res = nullptr; + ASSERT_EQ(spvReflectEvaluateResult(p_eval, p_type_arr->traits.array.spec_constant_op_ids[0], &res), SPV_REFLECT_RESULT_SUCCESS); + ASSERT_NE(res, nullptr); + ASSERT_NE(res->type, nullptr); + ASSERT_EQ(res->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + ASSERT_EQ(res->type->traits.numeric.scalar.width, 64); + ASSERT_EQ(res->data.numeric.scalar.value.sint32_value, 2); spvReflectDestroyShaderModule(&module_); } + +TEST(SpirvReflectSpecializationConstantTest, TestConvert) { + std::vector spirv_; + SpvReflectShaderModule module_; + const std::string spirv_path = "../tests/spec_constant/test_convert.spv"; + std::ifstream spirv_file(spirv_path, std::ios::binary | std::ios::ate); + std::streampos spirv_file_nbytes = spirv_file.tellg(); + spirv_file.seekg(0); + spirv_.resize(spirv_file_nbytes); + spirv_file.read(reinterpret_cast(spirv_.data()), spirv_.size()); + + SpvReflectResult result = + spvReflectCreateShaderModule2(SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT | SPV_REFLECT_MODULE_FLAG_NO_COPY, spirv_.size(), spirv_.data(), &module_); + ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result) + << "spvReflectCreateShaderModule() failed"; + + EXPECT_EQ(module_.entry_point_count, 1); + EXPECT_EQ(module_.entry_points[0].shader_stage, SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT); + ASSERT_EQ(module_.specialization_constant_count, 4); + SpvReflectEvaluation* p_eval = spvReflectGetEvaluationInterface(&module_); + ASSERT_NE(p_eval, nullptr); + + const SpvReflectValue* res = nullptr; + ASSERT_EQ(spvReflectEvaluateResult(p_eval, 9999, &res), SPV_REFLECT_RESULT_SUCCESS); + ASSERT_NE(res, nullptr); + ASSERT_NE(res->type, nullptr); + ASSERT_EQ(res->type->type_flags, SPV_REFLECT_TYPE_FLAG_FLOAT); + ASSERT_EQ(res->type->traits.numeric.scalar.width, 32); + ASSERT_EQ(res->data.numeric.scalar.value.float32_value, 1); + res = nullptr; + ASSERT_EQ(spvReflectEvaluateResult(p_eval, 10000, &res), SPV_REFLECT_RESULT_SUCCESS); + ASSERT_NE(res, nullptr); + ASSERT_NE(res->type, nullptr); + ASSERT_EQ(res->type->type_flags, SPV_REFLECT_TYPE_FLAG_FLOAT); + ASSERT_EQ(res->type->traits.numeric.scalar.width, 64); + ASSERT_EQ(res->data.numeric.scalar.value.float64_value, 1); + + ASSERT_EQ(module_.descriptor_binding_count, 4); + for (uint32_t i = 0; i < module_.descriptor_binding_count; ++i) { + ASSERT_NE(module_.descriptor_bindings[i].type_description, nullptr); + SpvReflectTypeDescription* p_type = module_.descriptor_bindings[i].type_description; + ASSERT_EQ(p_type->type_flags, SPV_REFLECT_TYPE_FLAG_STRUCT | SPV_REFLECT_TYPE_FLAG_EXTERNAL_BLOCK); + ASSERT_EQ(p_type->member_count, 2); + ASSERT_NE(p_type->members, nullptr); + SpvReflectTypeDescription* p_type_arr = &p_type->members[0]; + ASSERT_EQ(p_type_arr->type_flags, SPV_REFLECT_TYPE_FLAG_FLOAT | SPV_REFLECT_TYPE_FLAG_ARRAY); + ASSERT_EQ(p_type_arr->traits.array.dims_count, 1); + ASSERT_EQ(p_type_arr->traits.array.dims[0], 0xffffffff); + const SpvReflectValue* res = nullptr; + ASSERT_EQ(spvReflectEvaluateResult(p_eval, p_type_arr->traits.array.spec_constant_op_ids[0], &res), SPV_REFLECT_RESULT_SUCCESS); + ASSERT_NE(res, nullptr); + ASSERT_NE(res->type, nullptr); + ASSERT_EQ(res->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + ASSERT_EQ(res->type->traits.numeric.scalar.width, 32); + ASSERT_EQ(res->data.numeric.scalar.value.uint32_bool_value, 1); + } +} \ No newline at end of file From 4e9c21ebddad2332df424adb8ac96214c1455148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Mon, 8 Aug 2022 10:53:51 +0800 Subject: [PATCH 27/44] Clean up --- spirv_reflect.c | 33 ++++++++++++++++++++++++--------- spirv_reflect.h | 21 +++++++++------------ tests/spec_constant/rebuild.sh | 4 ++-- tests/test-spirv-reflect.cpp | 5 ++++- 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index f8060f7e..b01f8ded 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -1542,7 +1542,6 @@ static SpvReflectResult ParseDecorations(SpvReflectShaderModule* p_module, SpvRe case SpvDecorationBuiltIn: { p_target_decorations->is_built_in = true; uint32_t word_offset = p_node->word_offset + member_offset + 3; - // no rule specifies a result cannot be decorated twice. But let's assume this for now... SpvBuiltIn builtin_id; CHECKED_READU32_CAST(p_parser, word_offset, SpvBuiltIn, builtin_id); p_target_decorations->built_in = builtin_id; @@ -3583,13 +3582,11 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars p_module->specialization_constants = NULL; uint32_t constant_instruction_num = 0; - uint32_t instruction_size = 0; for (size_t i = 0; i < p_parser->node_count; ++i) { SpvReflectPrvNode* p_node = &(p_parser->nodes[i]); // constant types need to be tracked after parser is dead... if (IS_CONSTANT_OP(p_node->op)) { constant_instruction_num++; - instruction_size += p_node->word_count; } if (p_node->op == SpvOpSpecConstantTrue || p_node->op == SpvOpSpecConstantFalse || p_node->op == SpvOpSpecConstant) { p_module->specialization_constant_count++; @@ -3646,7 +3643,7 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars if (p_node->decorations.specialization_constant.value != (uint32_t)INVALID_VALUE) { for (uint32_t j = 0; j < index; ++j) { if (p_module->specialization_constants[j].constant_id == p_node->decorations.specialization_constant.value) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_DUPLICATE_SPEC_CONSTANT_NAME; + return SPV_REFLECT_RESULT_ERROR_SPIRV_DUPLICATE_ID; } } } @@ -6169,9 +6166,9 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect { switch (p_node->evaluation_state) { case SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED: - return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + return SPV_REFLECT_RESULT_ERROR_SPIRV_EVAL_TREE_INIT_FAILED; case SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED: - return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + return SPV_REFLECT_RESULT_ERROR_SPIRV_EVAL_TREE_INIT_FAILED; case SPV_REFLECT_EVALUATION_NODE_STATE_PENDING: p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_WORKING; break; @@ -6194,7 +6191,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect case SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED: break; case SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED: - return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + return SPV_REFLECT_RESULT_ERROR_SPIRV_EVAL_TREE_INIT_FAILED; case SPV_REFLECT_EVALUATION_NODE_STATE_PENDING: case SPV_REFLECT_EVALUATION_NODE_STATE_WORKING: case SPV_REFLECT_EVALUATION_NODE_STATE_DONE: @@ -6210,7 +6207,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect case SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED: break; case SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED: - return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR; + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; case SPV_REFLECT_EVALUATION_NODE_STATE_PENDING: case SPV_REFLECT_EVALUATION_NODE_STATE_WORKING: case SPV_REFLECT_EVALUATION_NODE_STATE_DONE: @@ -7406,18 +7403,36 @@ int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id return HaveNodeInTree(p_node, p_spec, false); } #else + SpvReflectEvaluation* spvReflectGetEvaluationInterface(SpvReflectShaderModule* p_module) { (void)p_module; return NULL; } +SpvReflectResult spvReflectSetSpecConstantValue(SpvReflectEvaluation* p_eval, uint32_t specId, SpvReflectScalarType type, const SpvReflectScalarValueData* value) +{ + (void)p_eval; + (void)specId; + (void)type; + (void)value; + return SPV_REFLECT_RESULT_ERROR_SPIRV_EVAL_TREE_INIT_FAILED; +} + +SpvReflectResult spvReflectGetSpecConstantValue(SpvReflectEvaluation* p_eval, uint32_t specId, const SpvReflectValue** value) +{ + (void)p_eval; + (void)specId; + (void)value; + return SPV_REFLECT_RESULT_ERROR_SPIRV_EVAL_TREE_INIT_FAILED; +} + SpvReflectResult spvReflectEvaluateResult(SpvReflectEvaluation* p_eval, uint32_t result_id, const SpvReflectValue** result) { (void)p_eval; (void)result_id; (void)result; - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + return SPV_REFLECT_RESULT_ERROR_SPIRV_EVAL_TREE_INIT_FAILED; } int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id, uint32_t specId) diff --git a/spirv_reflect.h b/spirv_reflect.h index 205d6f2a..172f3a20 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -80,9 +80,10 @@ typedef enum SpvReflectResult { SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_BLOCK_MEMBER_REFERENCE, SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ENTRY_POINT, SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_EXECUTION_MODE, - SPV_REFLECT_RESULT_ERROR_SPIRV_DUPLICATE_SPEC_CONSTANT_NAME, + SPV_REFLECT_RESULT_ERROR_SPIRV_DUPLICATE_ID, + SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE, SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION, - SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE + SPV_REFLECT_RESULT_ERROR_SPIRV_EVAL_TREE_INIT_FAILED } SpvReflectResult; /*! @enum SpvReflectModuleFlagBits @@ -96,15 +97,10 @@ SPV_REFLECT_MODULE_FLAG_NO_COPY - Disables copying of SPIR-V code This is flag is intended for cases where the memory overhead of storing the copied SPIR-V is undesirable. -SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT - copies constant - instructions for use with later evaluation. - -SPV_REFLECT_MODULE_FLAG_EVALUATE_NO_COPY - use p_code for later - evaluation. User need to make sure not to free memory. Code - pointed to need to be valid upon re-evaluation. Re-evaluation - MAY happen after changing any spec constant, and when a op is - evaluated for the first time. (behavior may be changed to only - when related constants are changed) +SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT - enables OpSpecXXX and + OpConstantXXX result id evaluation. Used for evaluating specialized + array sizes, and compute shader specialized WorkGroupSize + (LocalSizeId and WorkGroupSize builtin) */ typedef enum SpvReflectModuleFlagBits { SPV_REFLECT_MODULE_FLAG_NONE = 0x00000000, @@ -271,7 +267,8 @@ typedef enum SpvReflectGenerator { } SpvReflectGenerator; enum { - SPV_REFLECT_MAX_VECTOR_DIMS = 4, + // Vector16 capability allows larger vectors + SPV_REFLECT_MAX_VECTOR_DIMS = 16, SPV_REFLECT_MAX_ARRAY_DIMS = 32, SPV_REFLECT_MAX_DESCRIPTOR_SETS = 64, }; diff --git a/tests/spec_constant/rebuild.sh b/tests/spec_constant/rebuild.sh index f782b5bf..a21519f2 100644 --- a/tests/spec_constant/rebuild.sh +++ b/tests/spec_constant/rebuild.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Creates multi_entrypoint.spv from multi_entrypoint.glsl and -# multi_entrypoint.spv.dis.diff +# Creates test spv for specialization constant evaluation. +# Updating glsl may result in result id change, and patch file will need to update the number glslc -fshader-stage=comp --target-spv=spv1.5 test_orig.glsl -o test_32bit.spv spirv-dis test_32bit.spv > test_orig.spv.dis cp test_orig.spv.dis test_32bit.spv.dis diff --git a/tests/test-spirv-reflect.cpp b/tests/test-spirv-reflect.cpp index 3182ea9a..e6f1c91f 100644 --- a/tests/test-spirv-reflect.cpp +++ b/tests/test-spirv-reflect.cpp @@ -1463,6 +1463,8 @@ TEST(SpirvReflectSpecializationConstantTest, TestSpecParsingFloat) spvReflectDestroyShaderModule(&module_); } +#if SPIRV_REFLECT_ENABLE_CONSTANT_EVALUATION + TEST(SpirvReflectSpecializationConstantTest, TestEvaluate32) { std::vector spirv_; @@ -1655,4 +1657,5 @@ TEST(SpirvReflectSpecializationConstantTest, TestConvert) { ASSERT_EQ(res->type->traits.numeric.scalar.width, 32); ASSERT_EQ(res->data.numeric.scalar.value.uint32_bool_value, 1); } -} \ No newline at end of file +} +#endif From 477119a52ece7babf0c011bf18bc1bca9893792b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Mon, 8 Aug 2022 15:22:22 +0800 Subject: [PATCH 28/44] Fix gcc build warnings and errors gcc does not allow non-token concating. Also vec_size in size checking is unused after refactored to have multiple modes. --- spirv_reflect.c | 54 +++++++++++++++++++------------------------------ 1 file changed, 21 insertions(+), 33 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index b01f8ded..2cdf36b9 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -5585,7 +5585,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect } \ } -#define CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_result_node, p_op1_node, res, CLEANUP) \ +#define CHECK_IF_VECTOR_SIZE_MATCH_1OP(p_result_node, p_op1_node, res, CLEANUP) \ { \ if ((p_result_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ if (!((p_op1_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ @@ -5596,11 +5596,10 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ goto CLEANUP; \ } \ - vec_size = (p_result_node)->value.type->traits.numeric.vector.component_count; \ } \ } -#define CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, p_result_node, p_op1_node, p_op2_node, res, CLEANUP) \ +#define CHECK_IF_VECTOR_SIZE_MATCH_2OP(p_result_node, p_op1_node, p_op2_node, res, CLEANUP) \ { \ if ((p_result_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ if (!((p_op1_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ @@ -5619,7 +5618,6 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ goto CLEANUP; \ } \ - vec_size = (p_result_node)->value.type->traits.numeric.vector.component_count; \ } \ } @@ -5733,8 +5731,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect CHECK_IS_INTEGER_TYPE((simple_op_node)->id_operands[0], res, CLEANUP) \ CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node)->id_operands[0], res, CLEANUP) \ CHECK_WIDTH_MATCH((simple_op_node), (simple_op_node)->id_operands[0], res, CLEANUP) \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, (simple_op_node), (simple_op_node)->id_operands[0], res, CLEANUP) \ + CHECK_IF_VECTOR_SIZE_MATCH_1OP((simple_op_node), (simple_op_node)->id_operands[0], res, CLEANUP) \ } \ break; \ } \ @@ -5817,8 +5814,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect /* check agains result */ \ CHECK_WIDTH_MATCH(simple_op_node, (simple_op_node)->id_operands[0], res, CLEANUP) \ CHECK_WIDTH_MATCH(simple_op_node, (simple_op_node)->id_operands[1], res, CLEANUP) \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ } \ break; \ } \ @@ -5901,8 +5897,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ goto CLEANUP; \ } \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, (simple_op_node), (simple_op_node)->id_operands[0], (simple_op_node)->id_operands[1], res, CLEANUP) \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP((simple_op_node), (simple_op_node)->id_operands[0], (simple_op_node)->id_operands[1], res, CLEANUP) \ } \ break; \ } \ @@ -5961,16 +5956,16 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect goto CLEANUP; \ case 32: \ { \ - _32bit_type data = operand1->value.data.numeric.vector.value[i].value.##_32bit_member; \ + _32bit_type data = operand1->value.data.numeric.vector.value[i].value. _32bit_member; \ data operation##= shift_num; \ - (simple_op_node)->value.data.numeric.vector.value[i].value.##_32bit_member = data; \ + (simple_op_node)->value.data.numeric.vector.value[i].value. _32bit_member = data; \ } \ break; \ case 64: \ { \ - _64bit_type data = operand1->value.data.numeric.vector.value[i].value.##_64bit_member; \ + _64bit_type data = operand1->value.data.numeric.vector.value[i].value. _64bit_member; \ data operation##= shift_num; \ - (simple_op_node)->value.data.numeric.vector.value[i].value.##_64bit_member = data; \ + (simple_op_node)->value.data.numeric.vector.value[i].value. _64bit_member = data; \ } \ break; \ } \ @@ -6000,8 +5995,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect \ /* op1 and result must have same width */ \ CHECK_WIDTH_MATCH(simple_op_node, (simple_op_node)->id_operands[0], res, CLEANUP) \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ } \ break; \ } \ @@ -6065,8 +6059,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect CHECK_IS_BOOLEAN_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ } \ break; \ } \ @@ -6099,13 +6092,13 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect goto CLEANUP; \ case 32: \ (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1->value.data.numeric.vector.value[i].value.##_32bit_member \ - operation operand2->value.data.numeric.vector.value[i].value.##_32bit_member; \ + = operand1->value.data.numeric.vector.value[i].value. _32bit_member \ + operation operand2->value.data.numeric.vector.value[i].value. _32bit_member; \ break; \ case 64: \ (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1->value.data.numeric.vector.value[i].value.##_64bit_member \ - operation operand2->value.data.numeric.vector.value[i].value.##_64bit_member; \ + = operand1->value.data.numeric.vector.value[i].value. _64bit_member \ + operation operand2->value.data.numeric.vector.value[i].value. _64bit_member; \ break; \ } \ } \ @@ -6136,8 +6129,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ \ - uint32_t vec_size = 1; \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(vec_size, simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ } \ break; \ } \ @@ -6448,8 +6440,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; } - uint32_t vec_size = 1; - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_node, p_node->id_operands[0], res, CLEANUP) + CHECK_IF_VECTOR_SIZE_MATCH_1OP(p_node, p_node->id_operands[0], res, CLEANUP) } break; } @@ -6537,8 +6528,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; goto CLEANUP; } - uint32_t vec_size = 1; - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_node, p_node->id_operands[0], res, CLEANUP) + CHECK_IF_VECTOR_SIZE_MATCH_1OP(p_node, p_node->id_operands[0], res, CLEANUP) } break; } @@ -6617,8 +6607,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) // vector size must match - uint32_t vec_size = 1; - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_node, p_node->id_operands[0], res, CLEANUP) + CHECK_IF_VECTOR_SIZE_MATCH_1OP(p_node, p_node->id_operands[0], res, CLEANUP) } break; } @@ -7087,8 +7076,7 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect CHECK_IS_BOOLEAN_TYPE(p_node->id_operands[0], res, CLEANUP) CHECK_VECTOR_OR_SCALAR_TYPE(p_node->id_operands[0], res, CLEANUP) - uint32_t vec_size = 1; - CHECK_IF_VECTOR_SIZE_MATCH_1OP(vec_size, p_node, p_node->id_operands[0], res, CLEANUP) + CHECK_IF_VECTOR_SIZE_MATCH_1OP(p_node, p_node->id_operands[0], res, CLEANUP) } break; } @@ -7404,7 +7392,7 @@ int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id } #else -SpvReflectEvaluation* spvReflectGetEvaluationInterface(SpvReflectShaderModule* p_module) +SpvReflectEvaluation* spvReflectGetEvaluationInterface(const SpvReflectShaderModule* p_module) { (void)p_module; return NULL; From 83aab12384d949b49fc86370d85f3a974123fdac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Wed, 10 Aug 2022 09:25:16 +0800 Subject: [PATCH 29/44] Found some indentation inconsistency Also add checks for null pointers in interface functions. --- common/output_stream.cpp | 126 +++++++++++------------ spirv_reflect.c | 211 ++++++++++++++++++++------------------- spirv_reflect.h | 55 ++++------ 3 files changed, 190 insertions(+), 202 deletions(-) diff --git a/common/output_stream.cpp b/common/output_stream.cpp index 73364864..f1c17503 100644 --- a/common/output_stream.cpp +++ b/common/output_stream.cpp @@ -600,8 +600,8 @@ std::string ToStringComponentType(const SpvReflectTypeDescription& type, uint32_ } void ParseBlockMembersToTextLines( - spv_reflect::Evaluation obj, - const char* indent, int indent_depth, bool flatten_cbuffers, const std::string& parent_name, uint32_t member_count, const SpvReflectBlockVariable* p_members, std::vector* p_text_lines) + spv_reflect::Evaluation obj, + const char* indent, int indent_depth, bool flatten_cbuffers, const std::string& parent_name, uint32_t member_count, const SpvReflectBlockVariable* p_members, std::vector* p_text_lines) { const char* t = indent; for (uint32_t member_index = 0; member_index < member_count; ++member_index) { @@ -663,14 +663,14 @@ void ParseBlockMembersToTextLines( // dim = 0 means it's an unbounded array // if (dim > 0) { - if (dim == 0xFFFFFFFF) { - const SpvReflectValue* val; - SpvReflectResult res = obj.EvaluateResult(member.array.spec_constant_op_ids[array_dim_index], &val); - if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { - dim = val->data.numeric.scalar.value.uint32_bool_value; - } + if (dim == 0xFFFFFFFF) { + const SpvReflectValue* val; + SpvReflectResult res = obj.EvaluateResult(member.array.spec_constant_op_ids[array_dim_index], &val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { + dim = val->data.numeric.scalar.value.uint32_bool_value; } - ss_array << "[" << dim << "]"; + } + ss_array << "[" << dim << "]"; } else { ss_array << "[]"; @@ -707,11 +707,11 @@ void ParseBlockMembersToTextLines( for (uint32_t array_dim_index = 0; array_dim_index < member.array.dims_count; ++array_dim_index) { uint32_t dim = member.array.dims[array_dim_index]; if (dim == 0xFFFFFFFF) { - const SpvReflectValue* val; - SpvReflectResult res = obj.EvaluateResult(member.array.spec_constant_op_ids[array_dim_index], &val); - if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { - dim = val->data.numeric.scalar.value.uint32_bool_value; - } + const SpvReflectValue* val; + SpvReflectResult res = obj.EvaluateResult(member.array.spec_constant_op_ids[array_dim_index], &val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { + dim = val->data.numeric.scalar.value.uint32_bool_value; + } } ss_array << "[" << dim << "]"; } @@ -1038,7 +1038,7 @@ void StreamWriteInterfaceVariable(std::ostream& os, spv_reflect::Evaluation eval for (uint32_t dim_index = 0; dim_index < obj.array.dims_count; ++dim_index) { uint32_t dim = obj.array.dims[dim_index]; if (dim == 0xFFFFFFFF) { - const SpvReflectValue* val; + const SpvReflectValue* val; SpvReflectResult res = eval.EvaluateResult(obj.array.spec_constant_op_ids[dim_index], &val); if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { dim = val->data.numeric.scalar.value.uint32_bool_value; @@ -1091,43 +1091,43 @@ void StreamWriteSpecializationConstant(std::ostream& os, const SpvReflectSpecial os << "signed "; } else { - os << "unsigned "; + os << "unsigned "; } - os<< obj.type->traits.numeric.scalar.width <<" bit integer\n"; + os << obj.type->traits.numeric.scalar.width << " bit integer\n"; os << t << "default : "; // let's assume only 32 bit and 64 bit types (no 8 and 16 bit types here) if (obj.type->traits.numeric.scalar.width == 32) { - if (obj.type->traits.numeric.scalar.signedness) { - os << obj.default_value.value.sint32_value; - } - else { - os << obj.default_value.value.uint32_bool_value; - } + if (obj.type->traits.numeric.scalar.signedness) { + os << obj.default_value.value.sint32_value; + } + else { + os << obj.default_value.value.uint32_bool_value; + } } - else if(obj.type->traits.numeric.scalar.width == 64){ - if (obj.type->traits.numeric.scalar.signedness) { - os << obj.default_value.value.sint64_value; - } - else { - os << obj.default_value.value.uint64_value; - } + else if (obj.type->traits.numeric.scalar.width == 64) { + if (obj.type->traits.numeric.scalar.signedness) { + os << obj.default_value.value.sint64_value; + } + else { + os << obj.default_value.value.uint64_value; + } } else { - os << "default value not native in c/cpp"; + os << "default value not native in c/cpp"; } break; case 3: - os << obj.type->traits.numeric.scalar.width << " bit floating point\n"; - os << t << "default : "; - if (obj.type->traits.numeric.scalar.width == 32) { - os << obj.default_value.value.float32_value; - } - else if (obj.type->traits.numeric.scalar.width == 64) { - os << obj.default_value.value.float64_value; - } - else { - os << "default value not native in c/cpp"; - } + os << obj.type->traits.numeric.scalar.width << " bit floating point\n"; + os << t << "default : "; + if (obj.type->traits.numeric.scalar.width == 32) { + os << obj.default_value.value.float32_value; + } + else if (obj.type->traits.numeric.scalar.width == 64) { + os << obj.default_value.value.float64_value; + } + else { + os << "default value not native in c/cpp"; + } break; default: os << "unknown type"; @@ -1146,18 +1146,18 @@ void StreamWriteEntryPoint(std::ostream& os, spv_reflect::Evaluation eval, const else { os << "local size hint : "; } - if(obj.local_size.flags & 4) { - const SpvReflectValue* val; - SpvReflectResult res = eval.EvaluateResult(obj.local_size.x, &val); - if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == (SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_VECTOR)) - && (val->type->traits.numeric.scalar.width == 32)) { - os << "(" << val->data.numeric.vector.value[0].value.uint32_bool_value << ", " - << val->data.numeric.vector.value[1].value.uint32_bool_value << ", " - << val->data.numeric.vector.value[2].value.uint32_bool_value << ")"; - } - else { - os << "(failed evaluation of WorkGroupSize Builtin)"; - } + if (obj.local_size.flags & 4) { + const SpvReflectValue* val; + SpvReflectResult res = eval.EvaluateResult(obj.local_size.x, &val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == (SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_VECTOR)) + && (val->type->traits.numeric.scalar.width == 32)) { + os << "(" << val->data.numeric.vector.value[0].value.uint32_bool_value << ", " + << val->data.numeric.vector.value[1].value.uint32_bool_value << ", " + << val->data.numeric.vector.value[2].value.uint32_bool_value << ")"; + } + else { + os << "(failed evaluation of WorkGroupSize Builtin)"; + } } else if(obj.local_size.flags & 1) { os << "("; @@ -1192,18 +1192,18 @@ void StreamWriteEntryPoint(std::ostream& os, spv_reflect::Evaluation eval, const } } -void StreamWriteShaderModule(std::ostream& os, const spv_reflect::ShaderModule& obj, const char* indent) +void StreamWriteShaderModule(std::ostream& os, const SpvReflectShaderModule& obj, spv_reflect::Evaluation eval,const char* indent) { (void)indent; - os << "generator : " << ToStringGenerator(obj.GetShaderModule().generator) << "\n"; - os << "source lang : " << spvReflectSourceLanguage(obj.GetShaderModule().source_language) << "\n"; - os << "source lang ver : " << obj.GetShaderModule().source_language_version << "\n"; - os << "source file : " << (obj.GetShaderModule().source_file != NULL ? obj.GetShaderModule().source_file : "") << "\n"; + os << "generator : " << ToStringGenerator(obj.generator) << "\n"; + os << "source lang : " << spvReflectSourceLanguage(obj.source_language) << "\n"; + os << "source lang ver : " << obj.source_language_version << "\n"; + os << "source file : " << (obj.source_file != NULL ? obj.source_file : "") << "\n"; //os << "shader stage : " << ToStringShaderStage(obj.shader_stage) << "\n"; - for (uint32_t i = 0; i < obj.GetShaderModule().entry_point_count; ++i) { - StreamWriteEntryPoint(os, obj.GetEvaluation(), obj.GetShaderModule().entry_points[i], ""); - if (i < (obj.GetShaderModule().entry_point_count - 1)) { + for (uint32_t i = 0; i < obj.entry_point_count; ++i) { + StreamWriteEntryPoint(os, eval, obj.entry_points[i], ""); + if (i < (obj.entry_point_count - 1)) { os << "\n"; } } @@ -1223,7 +1223,7 @@ void WriteReflection(const spv_reflect::ShaderModule& obj, bool flatten_cbuffers const char* tt = " "; const char* ttt = " "; - StreamWriteShaderModule(os, obj, ""); + StreamWriteShaderModule(os, obj.GetShaderModule(), obj.GetEvaluation(), ""); uint32_t count = 0; std::vector variables; diff --git a/spirv_reflect.c b/spirv_reflect.c index 2cdf36b9..a494fbd6 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -5599,7 +5599,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect } \ } -#define CHECK_IF_VECTOR_SIZE_MATCH_2OP(p_result_node, p_op1_node, p_op2_node, res, CLEANUP) \ +#define CHECK_IF_VECTOR_SIZE_MATCH_2OP(p_result_node, p_op1_node, p_op2_node, res, CLEANUP) \ { \ if ((p_result_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) { \ if (!((p_op1_node)->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR)) { \ @@ -5731,7 +5731,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect CHECK_IS_INTEGER_TYPE((simple_op_node)->id_operands[0], res, CLEANUP) \ CHECK_VECTOR_OR_SCALAR_TYPE((simple_op_node)->id_operands[0], res, CLEANUP) \ CHECK_WIDTH_MATCH((simple_op_node), (simple_op_node)->id_operands[0], res, CLEANUP) \ - CHECK_IF_VECTOR_SIZE_MATCH_1OP((simple_op_node), (simple_op_node)->id_operands[0], res, CLEANUP) \ + CHECK_IF_VECTOR_SIZE_MATCH_1OP((simple_op_node), (simple_op_node)->id_operands[0], res, CLEANUP) \ } \ break; \ } \ @@ -5814,7 +5814,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect /* check agains result */ \ CHECK_WIDTH_MATCH(simple_op_node, (simple_op_node)->id_operands[0], res, CLEANUP) \ CHECK_WIDTH_MATCH(simple_op_node, (simple_op_node)->id_operands[1], res, CLEANUP) \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ } \ break; \ } \ @@ -5897,7 +5897,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; \ goto CLEANUP; \ } \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP((simple_op_node), (simple_op_node)->id_operands[0], (simple_op_node)->id_operands[1], res, CLEANUP) \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP((simple_op_node), (simple_op_node)->id_operands[0], (simple_op_node)->id_operands[1], res, CLEANUP) \ } \ break; \ } \ @@ -5956,16 +5956,16 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect goto CLEANUP; \ case 32: \ { \ - _32bit_type data = operand1->value.data.numeric.vector.value[i].value. _32bit_member; \ + _32bit_type data = operand1->value.data.numeric.vector.value[i].value. _32bit_member; \ data operation##= shift_num; \ - (simple_op_node)->value.data.numeric.vector.value[i].value. _32bit_member = data; \ + (simple_op_node)->value.data.numeric.vector.value[i].value. _32bit_member = data; \ } \ break; \ case 64: \ { \ - _64bit_type data = operand1->value.data.numeric.vector.value[i].value. _64bit_member; \ + _64bit_type data = operand1->value.data.numeric.vector.value[i].value. _64bit_member; \ data operation##= shift_num; \ - (simple_op_node)->value.data.numeric.vector.value[i].value. _64bit_member = data; \ + (simple_op_node)->value.data.numeric.vector.value[i].value. _64bit_member = data; \ } \ break; \ } \ @@ -5995,7 +5995,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect \ /* op1 and result must have same width */ \ CHECK_WIDTH_MATCH(simple_op_node, (simple_op_node)->id_operands[0], res, CLEANUP) \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ } \ break; \ } \ @@ -6059,7 +6059,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect CHECK_IS_BOOLEAN_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ } \ break; \ } \ @@ -6092,13 +6092,13 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect goto CLEANUP; \ case 32: \ (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1->value.data.numeric.vector.value[i].value. _32bit_member \ - operation operand2->value.data.numeric.vector.value[i].value. _32bit_member; \ + = operand1->value.data.numeric.vector.value[i].value. _32bit_member \ + operation operand2->value.data.numeric.vector.value[i].value. _32bit_member; \ break; \ case 64: \ (simple_op_node)->value.data.numeric.vector.value[i].value.uint32_bool_value \ - = operand1->value.data.numeric.vector.value[i].value. _64bit_member \ - operation operand2->value.data.numeric.vector.value[i].value. _64bit_member; \ + = operand1->value.data.numeric.vector.value[i].value. _64bit_member \ + operation operand2->value.data.numeric.vector.value[i].value. _64bit_member; \ break; \ } \ } \ @@ -6129,7 +6129,7 @@ SpvReflectResult CopyValueData(const SpvReflectTypeDescription* type, SpvReflect CHECK_IS_INTEGER_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ CHECK_VECTOR_OR_SCALAR_TYPE(simple_op_node->id_operands[1], res, CLEANUP) \ \ - CHECK_IF_VECTOR_SIZE_MATCH_2OP(simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ } \ break; \ } \ @@ -7279,116 +7279,123 @@ static SpvReflectResult SPIRV_REFLECT_FORCEINLINE EvaluateResult_Impl(SpvReflect SpvReflectEvaluation* spvReflectGetEvaluationInterface(const SpvReflectShaderModule* p_module) { - // build ast here. - return p_module->_internal->evaluator; + if(!p_module) return NULL; + return p_module->_internal->evaluator; } bool HaveNodeInTree(SpvReflectPrvEvaluationNode* p_node_root, const SpvReflectPrvEvaluationNode* p_node_expected, bool flag_changed) { - if (p_node_root == p_node_expected) { - if (flag_changed) { - p_node_root->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED; - } - return true; + if (p_node_root == p_node_expected) { + if (flag_changed) { + p_node_root->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED; } - for (uint32_t i = 0; i < p_node_root->num_id_operands; ++i) { - if (HaveNodeInTree(p_node_root->id_operands[i], p_node_expected, flag_changed)) { - if (flag_changed) { - p_node_root->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED; - } - return true; - } + return true; + } + for (uint32_t i = 0; i < p_node_root->num_id_operands; ++i) { + if (HaveNodeInTree(p_node_root->id_operands[i], p_node_expected, flag_changed)) { + if (flag_changed) { + p_node_root->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED; + } + return true; } - return false; + } + return false; } SpvReflectResult spvReflectSetSpecConstantValue(SpvReflectEvaluation* p_eval, uint32_t specId, SpvReflectScalarType type, const SpvReflectScalarValueData* value) { - SpvReflectPrvEvaluationNode* p_node = FindSpecIdNode(p_eval, specId); - if (!p_node) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; - } - switch (type) { - default: - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - case SPIRV_REFLECT_SCALAR_TYPE_BOOL: - if (p_node->value.type->type_flags != SPV_REFLECT_TYPE_FLAG_BOOL) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - break; - case SPIRV_REFLECT_SCALAR_TYPE_I32: - case SPIRV_REFLECT_SCALAR_TYPE_I64: - if (p_node->value.type->type_flags != SPV_REFLECT_TYPE_FLAG_INT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - break; - case SPIRV_REFLECT_SCALAR_TYPE_F32: - case SPIRV_REFLECT_SCALAR_TYPE_F64: - if (p_node->value.type->type_flags != SPV_REFLECT_TYPE_FLAG_FLOAT) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - break; - } - switch (type) { - default: - break; - case SPIRV_REFLECT_SCALAR_TYPE_I32: - case SPIRV_REFLECT_SCALAR_TYPE_F32: - if (p_node->value.type->traits.numeric.scalar.width != 32) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - break; - case SPIRV_REFLECT_SCALAR_TYPE_I64: - case SPIRV_REFLECT_SCALAR_TYPE_F64: - if (p_node->value.type->traits.numeric.scalar.width != 64) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; - } - break; - } - p_node->value.data.numeric.scalar = *value; - p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED; - // update state tracking here... - for (uint32_t i = 0; i < p_eval->node_count; ++i) { - if (p_eval->nodes[i].evaluation_state == SPV_REFLECT_EVALUATION_NODE_STATE_DONE - && HaveNodeInTree(&p_eval->nodes[i], p_node, true)) { - p_eval->nodes[i].evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED; - } + if (!p_eval || !value) { + return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; + } + SpvReflectPrvEvaluationNode* p_node = FindSpecIdNode(p_eval, specId); + if (!p_node) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; + } + switch (type) { + default: + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + case SPIRV_REFLECT_SCALAR_TYPE_BOOL: + if (p_node->value.type->type_flags != SPV_REFLECT_TYPE_FLAG_BOOL) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + break; + case SPIRV_REFLECT_SCALAR_TYPE_I32: + case SPIRV_REFLECT_SCALAR_TYPE_I64: + if (p_node->value.type->type_flags != SPV_REFLECT_TYPE_FLAG_INT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + break; + case SPIRV_REFLECT_SCALAR_TYPE_F32: + case SPIRV_REFLECT_SCALAR_TYPE_F64: + if (p_node->value.type->type_flags != SPV_REFLECT_TYPE_FLAG_FLOAT) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + break; + } + switch (type) { + default: + break; + case SPIRV_REFLECT_SCALAR_TYPE_I32: + case SPIRV_REFLECT_SCALAR_TYPE_F32: + if (p_node->value.type->traits.numeric.scalar.width != 32) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + break; + case SPIRV_REFLECT_SCALAR_TYPE_I64: + case SPIRV_REFLECT_SCALAR_TYPE_F64: + if (p_node->value.type->traits.numeric.scalar.width != 64) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE; + } + break; + } + p_node->value.data.numeric.scalar = *value; + p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED; + // update state tracking here... + for (uint32_t i = 0; i < p_eval->node_count; ++i) { + if (p_eval->nodes[i].evaluation_state == SPV_REFLECT_EVALUATION_NODE_STATE_DONE + && HaveNodeInTree(&p_eval->nodes[i], p_node, true)) { + p_eval->nodes[i].evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED; } - return SPV_REFLECT_RESULT_SUCCESS; + } + return SPV_REFLECT_RESULT_SUCCESS; } SpvReflectResult spvReflectGetSpecConstantValue(SpvReflectEvaluation* p_eval, uint32_t specId, const SpvReflectValue** value) { - SpvReflectPrvEvaluationNode* p_node = FindSpecIdNode(p_eval, specId); - if (!p_node) { - return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; - } - *value = &p_node->value; - return SPV_REFLECT_RESULT_SUCCESS; + if(!p_eval || !value) { + return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; + } + SpvReflectPrvEvaluationNode* p_node = FindSpecIdNode(p_eval, specId); + if (!p_node) { + return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE; + } + *value = &p_node->value; + return SPV_REFLECT_RESULT_SUCCESS; } SpvReflectResult spvReflectEvaluateResult(SpvReflectEvaluation* p_eval, uint32_t result_id, const SpvReflectValue** result) { - if (!result || !p_eval) { - return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; - } - SpvReflectPrvEvaluationNode* p_node = FindEvaluationNode(p_eval, result_id); - SpvReflectResult res = EvaluateResult_Do(p_node); - *result = &p_node->value; - return res; + if (!result || !p_eval) { + return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; + } + SpvReflectPrvEvaluationNode* p_node = FindEvaluationNode(p_eval, result_id); + SpvReflectResult res = EvaluateResult_Do(p_node); + *result = &p_node->value; + return res; } int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id, uint32_t specId) { - SpvReflectPrvEvaluationNode* p_node = FindEvaluationNode(p_eval, result_id); - if (!p_node) { - return 0; - } - SpvReflectPrvEvaluationNode* p_spec = FindSpecIdNode(p_eval, specId); - if (!p_node) { - return 0; - } - return HaveNodeInTree(p_node, p_spec, false); + if (!p_eval) return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; + SpvReflectPrvEvaluationNode* p_node = FindEvaluationNode(p_eval, result_id); + if (!p_node) { + return 0; + } + SpvReflectPrvEvaluationNode* p_spec = FindSpecIdNode(p_eval, specId); + if (!p_node) { + return 0; + } + return HaveNodeInTree(p_node, p_spec, false); } #else diff --git a/spirv_reflect.h b/spirv_reflect.h index 172f3a20..e3a236bd 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -346,27 +346,27 @@ typedef struct SpvReflectTypeDescription { typedef struct SpvReflectScalarValueData { - union { - /* small types not implemented yet... */ - /* also remember float16 */ - uint8_t uint8_value; - int8_t sint8_value; - uint16_t uint16_value; - int16_t sint16_value; - /* types that are currently supported */ - uint32_t uint32_bool_value; - int32_t sint32_value; - float float32_value; - uint64_t uint64_value; - int64_t sint64_value; - double float64_value; - } value; - // for use with OpUndef - int undefined_value; + union { + /* small types not implemented yet... */ + /* also remember float16 */ + uint8_t uint8_value; + int8_t sint8_value; + uint16_t uint16_value; + int16_t sint16_value; + /* types that are currently supported */ + uint32_t uint32_bool_value; + int32_t sint32_value; + float float32_value; + uint64_t uint64_value; + int64_t sint64_value; + double float64_value; + } value; + // for use with OpUndef + int undefined_value; } SpvReflectScalarValueData; typedef struct SpvReflectVectorValueData { - SpvReflectScalarValueData value[SPV_REFLECT_MAX_VECTOR_DIMS]; + SpvReflectScalarValueData value[SPV_REFLECT_MAX_VECTOR_DIMS]; } SpvReflectVectorValueData; // only scalar, vector types can evaluate values for now... @@ -1559,16 +1559,6 @@ typedef enum SpvReflectScalarType { SPIRV_REFLECT_SCALAR_TYPE_F64 } SpvReflectScalarType; -/*! @fn spvReflectSetSpecConstantValue - @brief Sets the current value of specialization constant. Type must follow c/c++ type aliasing rules. - @param p_eval Pointer to an instance of SpvReflectEvaluation. - @param specId Specialization constant id of the constant. - @param type Type of user specified value. For error checking. - @param value User provided value. - @return If successful, returns SPV_REFLECT_RESULT_SUCCESS. - Otherwise, the error code indicates the cause of - the failure. -*/ /*! @fn spvReflectSetSpecConstantValue @brief Sets the current value of specialization constant. Type must follow c/c++ type aliasing rules. @param p_eval Pointer to an instance of SpvReflectEvaluation. @@ -1581,15 +1571,6 @@ the failure. */ SpvReflectResult spvReflectSetSpecConstantValue(SpvReflectEvaluation* p_eval, uint32_t specId, SpvReflectScalarType type, const SpvReflectScalarValueData* value); -/*! @fn spvReflectGetSpecConstantValue - @brief Get the current value of specialization constant. Type must follow c/c++ type aliasing rules. - @param p_eval Pointer to an instance of SpvReflectEvaluation. - @param specId Specialization constant id of the constant. - @param value Current value. - @return If successful, returns SPV_REFLECT_RESULT_SUCCESS. - Otherwise, the error code indicates the cause of - the failure. -*/ /*! @fn spvReflectGetSpecConstantValue @brief Get the current value of specialization constant. Type must follow c/c++ type aliasing rules. @param p_eval Pointer to an instance of SpvReflectEvaluation. From 4640fd6a5b6fc164aeea36710bce41bb489e148b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Fri, 12 Aug 2022 15:58:55 +0800 Subject: [PATCH 30/44] Fix member indentation Nested struct member in union uses a few extra indent to be clear. --- spirv_reflect.c | 18 +++++++++--------- spirv_reflect.h | 44 ++++++++++++++++++++++---------------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index f61e9ff2..3a21b7c8 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -253,18 +253,18 @@ typedef struct SpvReflectPrvEvaluationNode { // add another 2 passes if need explicit initialization and free... union InstructionPrivate { // used only in preprocess passes to replace parser FindNode - SpvReflectPrvNode* uninitialized; + SpvReflectPrvNode* uninitialized; struct VectorShuffle { - uint8_t idx[SPV_REFLECT_MAX_VECTOR_DIMS]; - } vector_shuffle; + uint8_t idx[SPV_REFLECT_MAX_VECTOR_DIMS]; + } vector_shuffle; struct CompositeExtract { - const SpvReflectTypeDescription* src_type; - SpvReflectValueData* src_data; - } composite_extract; + const SpvReflectTypeDescription* src_type; + SpvReflectValueData* src_data; + } composite_extract; struct CompositeInsert { - const SpvReflectTypeDescription* dst_type; - SpvReflectValueData* dst_data; - }composite_insert; + const SpvReflectTypeDescription* dst_type; + SpvReflectValueData* dst_data; + } composite_insert; } instruction_private; } SpvReflectPrvEvaluationNode; // clang-format on diff --git a/spirv_reflect.h b/spirv_reflect.h index 3950d795..6f031cca 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -349,56 +349,56 @@ typedef struct SpvReflectScalarValueData { union { /* small types not implemented yet... */ /* also remember float16 */ - uint8_t uint8_value; - int8_t sint8_value; - uint16_t uint16_value; - int16_t sint16_value; + uint8_t uint8_value; + int8_t sint8_value; + uint16_t uint16_value; + int16_t sint16_value; /* types that are currently supported */ - uint32_t uint32_bool_value; - int32_t sint32_value; - float float32_value; - uint64_t uint64_value; - int64_t sint64_value; - double float64_value; + uint32_t uint32_bool_value; + int32_t sint32_value; + float float32_value; + uint64_t uint64_value; + int64_t sint64_value; + double float64_value; } value; // for use with OpUndef - int undefined_value; + int undefined_value; } SpvReflectScalarValueData; typedef struct SpvReflectVectorValueData { - SpvReflectScalarValueData value[SPV_REFLECT_MAX_VECTOR_DIMS]; + SpvReflectScalarValueData value[SPV_REFLECT_MAX_VECTOR_DIMS]; } SpvReflectVectorValueData; // only scalar, vector types can evaluate values for now... // this struct is not meant to be created on user stack, // instead in a internal dictionary and give user const ptr to read. typedef union SpvReflectValueNumericData { - SpvReflectScalarValueData scalar; - SpvReflectVectorValueData vector; + SpvReflectScalarValueData scalar; + SpvReflectVectorValueData vector; } SpvReflectValueNumericData; typedef union SpvReflectValueData { - SpvReflectValueNumericData numeric; + SpvReflectValueNumericData numeric; } SpvReflectValueData; typedef struct SpvReflectValue { // never null in valid spirv // means result type id - SpvReflectTypeDescription* type; - SpvReflectValueData data; + SpvReflectTypeDescription* type; + SpvReflectValueData data; }SpvReflectValue; /*! @struct SpvReflectSpecializationConstant */ typedef struct SpvReflectSpecializationConstant { - uint32_t spirv_id; - uint32_t constant_id; + uint32_t spirv_id; + uint32_t constant_id; - SpvReflectTypeDescription* type; - const char* name; + SpvReflectTypeDescription* type; + const char* name; - SpvReflectScalarValueData default_value; + SpvReflectScalarValueData default_value; } SpvReflectSpecializationConstant; /*! @struct SpvReflectInterfaceVariable From 8ad92900349faf15e5fe90b9b0de7bfbc6006dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sun, 14 Aug 2022 02:47:08 +0800 Subject: [PATCH 31/44] Add structure filling Add functionality to fill vulkan structure. No test yet. --- spirv_reflect.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++-- spirv_reflect.h | 26 ++++++++++++++++++ 2 files changed, 94 insertions(+), 2 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index 3a21b7c8..3cb8de24 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -244,6 +244,7 @@ typedef struct SpvReflectPrvEvaluationNode { SpvReflectValue value; uint32_t specId; + bool specialized; uint32_t num_id_operands; SpvReflectPrvEvaluationNode** id_operands; @@ -596,7 +597,7 @@ static SpvReflectPrvNode* FindNode( } static SpvReflectPrvEvaluationNode* FindEvaluationNode( - SpvReflectEvaluation* p_eval, + const SpvReflectEvaluation* p_eval, uint32_t result_id) { SpvReflectPrvEvaluationNode* p_node = NULL; @@ -611,7 +612,7 @@ static SpvReflectPrvEvaluationNode* FindEvaluationNode( } static SpvReflectPrvEvaluationNode* FindSpecIdNode( - SpvReflectEvaluation* p_eval, + const SpvReflectEvaluation* p_eval, uint32_t specid) { SpvReflectPrvEvaluationNode* p_node = NULL; @@ -7400,6 +7401,7 @@ SpvReflectResult spvReflectSetSpecConstantValue(SpvReflectEvaluation* p_eval, ui break; } p_node->value.data.numeric.scalar = *value; + p_node->specialized = true; p_node->evaluation_state = SPV_REFLECT_EVALUATION_NODE_STATE_UPDATED; // update state tracking here... for (uint32_t i = 0; i < p_eval->node_count; ++i) { @@ -7448,6 +7450,61 @@ int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id } return HaveNodeInTree(p_node, p_spec, false); } + + +SpvReflectResult spvReflectGetSpecializationInfo(const SpvReflectEvaluation* p_eval, VkSpecializationInfo* info, VkSpecializationMapEntry* p_modifiable, uint32_t num_entries) +{ + if(!info || !p_eval) { + return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; + } + if (!p_modifiable) { + uint32_t count = 0; + for (uint32_t i = 0; i < p_eval->member_type_finder->specialization_constant_count; ++i) { + SpvReflectPrvEvaluationNode* p_node = FindSpecIdNode(p_eval, p_eval->member_type_finder->specialization_constants[i].constant_id); + if (p_node->specialized) { + ++count; + } + } + info->mapEntryCount = count; + } + else { + uint32_t count = 0; + uint32_t last_element = 0; + uint32_t first_element = 0xffffffff; + uint32_t last_element_size = 0; + for (uint32_t i = 0; i < p_eval->member_type_finder->specialization_constant_count && count < num_entries; ++i) { + SpvReflectPrvEvaluationNode* p_node = FindSpecIdNode(p_eval, p_eval->member_type_finder->specialization_constants[i].constant_id); + if (p_node->specialized) { + ++count; + p_modifiable[count].constantID = p_node->specId; + p_modifiable[count].size = p_node->value.type->traits.numeric.scalar.width / 8; + // VUID-VkSpecializationMapEntry-constantID-00776 + // For a constantID specialization constant declared in a shader, size must match the byte size of the constantID. + // If the specialization constant is of type boolean, size must be the byte size of VkBool32 + if(p_node->value.type->type_flags & SPV_REFLECT_TYPE_FLAG_BOOL){ + p_modifiable[count].size = 4; + } + const uint32_t node_size = sizeof(*p_node); + uint32_t idx = (uint32_t)(p_node-p_eval->nodes); + p_modifiable[count].offset = idx * node_size; + if(idx > last_element) { + last_element = idx; + last_element_size = (uint32_t)p_modifiable[count].size; + } + if(idx < first_element){ + first_element = idx; + } + } + } + info->mapEntryCount = count; + if(count){ + info->pData = ((uint8_t*)(p_eval->nodes + first_element)) + offsetof(SpvReflectPrvEvaluationNode, value.data.numeric.scalar.value); + info->dataSize = sizeof(SpvReflectPrvEvaluationNode) * (last_element - first_element) + last_element_size; + } + } + return SPV_REFLECT_RESULT_SUCCESS; +} + #else SpvReflectEvaluation* spvReflectGetEvaluationInterface(const SpvReflectShaderModule* p_module) @@ -7489,5 +7546,14 @@ int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id return 0; } +SpvReflectResult spvReflectGetSpecializationInfo(const SpvReflectEvaluation* p_eval, VkSpecializationInfo* info, VkSpecializationMapEntry* p_modifiable, uint32_t num_entries) +{ + (void)p_eval; + (void)info; + (void)p_modifiable; + (void)num_entries; + return SPV_REFLECT_RESULT_ERROR_SPIRV_EVAL_TREE_INIT_FAILED; +} + #endif diff --git a/spirv_reflect.h b/spirv_reflect.h index 6f031cca..3c2108df 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -1617,6 +1617,32 @@ SpvReflectResult spvReflectEvaluateResult(SpvReflectEvaluation* p_eval, uint32_t */ int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id, uint32_t specId); +/* need delaration compatible with vulkan.h, has to be const... */ +typedef struct VkSpecializationMapEntry { + uint32_t constantID; + uint32_t offset; + size_t size; +} VkSpecializationMapEntry; + +typedef struct VkSpecializationInfo { + uint32_t mapEntryCount; + const VkSpecializationMapEntry* pMapEntries; + size_t dataSize; + const void* pData; +} VkSpecializationInfo; + +/* @fn spvReflectGetSpecializationInfo + @brief Call with nullptr to retrieve size of spec in entryCount, then allocate and call again. + @param p_eval The evaluation interface + @param info The info to be retrieved + @param p_modifiable Pointer to modifiable entries allocated by user + @param num_entries size of user supplied array + @return If successful, returns SPV_REFLECT_RESULT_SUCCESS. + Otherwise, the error code indicates the cause of + the failure. +*/ + +SpvReflectResult spvReflectGetSpecializationInfo(const SpvReflectEvaluation* p_eval, VkSpecializationInfo* info, VkSpecializationMapEntry* p_modifiable, uint32_t num_entries); #if defined(__cplusplus) }; From 5f73ca4ae6d676d4fba66b5873d8c6220a383212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sun, 14 Aug 2022 13:13:52 +0800 Subject: [PATCH 32/44] Add cpp wrapper function --- spirv_reflect.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spirv_reflect.h b/spirv_reflect.h index 3c2108df..9eeee01f 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -1803,6 +1803,15 @@ class Evaluation { return false; } } + SpvReflectResult GetSpecializationInfo(VkSpecializationInfo* info, VkSpecializationMapEntry* p_modifiable, uint32_t num_entries) + { + if (p_eval) { + return spvReflectGetSpecializationInfo(p_eval, info, p_modifiable, num_entries); + } + else{ + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + } + } private: SpvReflectEvaluation* p_eval; }; From 015bc9eee886fce5f4f593873f1cf8628d434d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Mon, 15 Aug 2022 16:54:47 +0800 Subject: [PATCH 33/44] Fix build with vulkan.h and add evaluation duplication Should not add duplicate definition in header. --- spirv_reflect.c | 128 ++++++++++++++++++++++++++++++++++++++++++++---- spirv_reflect.h | 37 ++++++++------ 2 files changed, 141 insertions(+), 24 deletions(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index 3cb8de24..bfe2a4f2 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -281,8 +281,11 @@ typedef struct SpvReflectEvaluation { uint32_t node_count; SpvReflectPrvEvaluationNode* nodes; - SpvReflectPrvEvaluationNode** id_operand_buffer; - uint32_t* literal_word_buffer; + uint32_t id_operand_count; + SpvReflectPrvEvaluationNode** id_operands; + + uint32_t literal_word_count; + uint32_t* literal_words; // ohh I hope I could decouple this... But FindType uses this... // just a reference @@ -3769,14 +3772,16 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars } } if (id_operands) { - p_eval->id_operand_buffer = (SpvReflectPrvEvaluationNode**)malloc(id_operands * sizeof(SpvReflectPrvEvaluationNode*)); - if (IsNull(p_eval->id_operand_buffer)) { + p_eval->id_operands = (SpvReflectPrvEvaluationNode**)malloc(id_operands * sizeof(SpvReflectPrvEvaluationNode*)); + p_eval->id_operand_count = id_operands; + if (IsNull(p_eval->id_operands)) { return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; } } if (literal_words) { - p_eval->literal_word_buffer = (uint32_t*)malloc(literal_words * sizeof(uint32_t)); - if (IsNull(p_eval->literal_word_buffer)) { + p_eval->literal_words = (uint32_t*)malloc(literal_words * sizeof(uint32_t)); + p_eval->literal_word_count = literal_words; + if (IsNull(p_eval->literal_words)) { return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; } } @@ -3785,8 +3790,8 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars for (uint32_t i = 0; i < p_eval->node_count; ++i) { SpvReflectPrvEvaluationNode* p_ev_node = &p_eval->nodes[i]; if (!IS_CONSTANT_LITERAL_OP(p_ev_node->op) && p_ev_node->evaluation_state == SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED) { - p_ev_node->id_operands = p_eval->id_operand_buffer + id_offset; - p_ev_node->literal_words = p_eval->literal_word_buffer + literal_offset; + p_ev_node->id_operands = p_eval->id_operands + id_offset; + p_ev_node->literal_words = p_eval->literal_words + literal_offset; literal_offset += p_ev_node->num_literal_words; id_offset += p_ev_node->num_id_operands; } @@ -3809,8 +3814,8 @@ static void DestroyEvaluator(SpvReflectEvaluation* evaluator) { SafeFree(evaluator->nodes); - SafeFree(evaluator->id_operand_buffer); - SafeFree(evaluator->literal_word_buffer); + SafeFree(evaluator->id_operands); + SafeFree(evaluator->literal_words); } @@ -7451,6 +7456,24 @@ int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id return HaveNodeInTree(p_node, p_spec, false); } +#if _SPIRV_REFLECT_USE_VULKAN_H_ +#include +#else +// Provided by VK_VERSION_1_0 +typedef struct VkSpecializationInfo { + uint32_t mapEntryCount; + const VkSpecializationMapEntry* pMapEntries; + size_t dataSize; + const void* pData; +} VkSpecializationInfo; +// Provided by VK_VERSION_1_0 +typedef struct VkSpecializationMapEntry { + uint32_t constantID; + uint32_t offset; + size_t size; +} VkSpecializationMapEntry; +#endif + SpvReflectResult spvReflectGetSpecializationInfo(const SpvReflectEvaluation* p_eval, VkSpecializationInfo* info, VkSpecializationMapEntry* p_modifiable, uint32_t num_entries) { @@ -7505,6 +7528,81 @@ SpvReflectResult spvReflectGetSpecializationInfo(const SpvReflectEvaluation* p_e return SPV_REFLECT_RESULT_SUCCESS; } +SpvReflectEvaluation* spvReflectDuplicateEvaluation(const SpvReflectEvaluation* p_eval) +{ + if(!p_eval) return NULL; + SpvReflectEvaluation* p_copied = (SpvReflectEvaluation*)calloc(1, sizeof(SpvReflectEvaluation)); + if(!p_copied) return NULL; + if (p_eval->node_count) { + p_copied->nodes = (SpvReflectPrvEvaluationNode*)calloc(p_eval->node_count, sizeof(SpvReflectPrvEvaluationNode)); + if (!p_copied->nodes) { + goto CLEANUP; + } + p_copied->node_count = p_eval->node_count; + } + if (p_eval->literal_word_count) { + p_copied->literal_words = (uint32_t*)malloc(p_eval->literal_word_count * sizeof(uint32_t)); + if (!p_copied->literal_words) { + goto CLEANUP; + } + p_copied->literal_word_count = p_eval->literal_word_count; + memcpy(p_copied->literal_words, p_eval->literal_words, p_eval->literal_word_count*sizeof(uint32_t)); + } + if (p_eval->id_operand_count) { + p_copied->id_operands = (SpvReflectPrvEvaluationNode**)malloc(p_eval->id_operand_count * sizeof(SpvReflectPrvEvaluationNode*)); + if (!p_copied->id_operands) { + goto CLEANUP; + } + p_copied->id_operand_count = p_eval->id_operand_count; + } + // build the tree again... + memcpy(p_copied->nodes, p_eval->nodes, p_eval->node_count*sizeof(SpvReflectPrvEvaluationNode)); + for (uint32_t i = 0; i < p_eval->node_count; ++i) { + SPV_REFLECT_ASSERT(p_copied->nodes[i].num_id_operands == p_eval->nodes[i].num_id_operands); + for (uint32_t j = 0; j < p_eval->nodes[i].num_id_operands; ++j) { + p_copied->nodes[i].id_operands[j] = &p_copied->nodes[p_eval->nodes[i].id_operands[j] - p_eval->nodes]; + } + // need to copy instruction private too... + if(p_copied->nodes[i].op == SpvOpSpecConstantOp){ + switch (p_copied->nodes[i].specOp) { + default: break; + case SpvOpVectorShuffle: + // literal does not need pointer update. + break; + case SpvOpCompositeExtract: + p_copied->nodes[i].instruction_private.composite_extract.src_data = + (SpvReflectValueData*)(((uint8_t*)p_copied->nodes) + // plus offset of the original pointer + +(((uint8_t*)(p_eval->nodes[i].instruction_private.composite_extract.src_data))-(uint8_t*)p_eval->nodes)); + break; + case SpvOpCompositeInsert: + p_copied->nodes[i].instruction_private.composite_insert.dst_data = + (SpvReflectValueData*)(((uint8_t*)p_copied->nodes) + // plus offset of the original pointer + + (((uint8_t*)(p_eval->nodes[i].instruction_private.composite_insert.dst_data)) - (uint8_t*)p_eval->nodes)); + break; + } + } + } + + return p_copied; + + CLEANUP: + spvReflectDestroyDuplicatedEvaluation(p_copied); + return NULL; +} + +void spvReflectDestroyDuplicatedEvaluation(SpvReflectEvaluation* p_eval) +{ + if(!p_eval) return; + if(p_eval->member_type_finder->_internal->evaluator == p_eval) { + return; + } + DestroyEvaluator(p_eval); + SafeFree(p_eval); +} + + #else SpvReflectEvaluation* spvReflectGetEvaluationInterface(const SpvReflectShaderModule* p_module) @@ -7555,5 +7653,15 @@ SpvReflectResult spvReflectGetSpecializationInfo(const SpvReflectEvaluation* p_e return SPV_REFLECT_RESULT_ERROR_SPIRV_EVAL_TREE_INIT_FAILED; } +SpvReflectEvaluation* spvReflectDuplicateEvaluation(const SpvReflectEvaluation* p_eval) +{ + (void)p_eval; + return NULL; +} + +void spvReflectDestroyDuplicatedEvaluation(SpvReflectEvaluation* p_eval) +{ + (void)p_eval; +} #endif diff --git a/spirv_reflect.h b/spirv_reflect.h index 9eeee01f..fa240b38 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -1553,11 +1553,28 @@ const char* spvReflectBlockVariableTypeName( /*! @fn spvReflectGetEvaluationInterface @brief Retrieves the handle for evaluation @param p_module Pointer to an instance of SpvReflectShaderModule. - @return If successful, returns the evaluation instance. + @return If successful, returns the internal evaluation instance. Otherwise, returns NULL. */ SpvReflectEvaluation* spvReflectGetEvaluationInterface(const SpvReflectShaderModule* p_module); +/*! @fn spvReflectDuplicateEvaluation + @brief Duplicates the internal state of the handle for evaluation, useful when one needs + multiple instances of different specialization constant states. This handle needs + to be explicitly destroyed (not tied to module lifetime). This also cannot outlive + type info. + @param p_eval The original handle to be duplicated + @return If successful, returns a copied evaluation interface, with same state. + Otherwise, returns NULL. +*/ +SpvReflectEvaluation* spvReflectDuplicateEvaluation(const SpvReflectEvaluation* p_eval); + +/*! @fn spvReflectDuplicateEvaluation + @brief Destroys handle from spvReflectDuplicateEvaluation + @param p_eval The handle to be destroyed. +*/ +void spvReflectDestroyDuplicatedEvaluation(SpvReflectEvaluation* p_eval); + typedef enum SpvReflectScalarType { SPIRV_REFLECT_SCALAR_TYPE_INVALID, SPIRV_REFLECT_SCALAR_TYPE_BOOL, @@ -1617,19 +1634,11 @@ SpvReflectResult spvReflectEvaluateResult(SpvReflectEvaluation* p_eval, uint32_t */ int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id, uint32_t specId); -/* need delaration compatible with vulkan.h, has to be const... */ -typedef struct VkSpecializationMapEntry { - uint32_t constantID; - uint32_t offset; - size_t size; -} VkSpecializationMapEntry; - -typedef struct VkSpecializationInfo { - uint32_t mapEntryCount; - const VkSpecializationMapEntry* pMapEntries; - size_t dataSize; - const void* pData; -} VkSpecializationInfo; +/* + types used, but defined in vulkan.h +*/ +typedef struct VkSpecializationInfo VkSpecializationInfo; +typedef struct VkSpecializationMapEntry VkSpecializationMapEntry; /* @fn spvReflectGetSpecializationInfo @brief Call with nullptr to retrieve size of spec in entryCount, then allocate and call again. From 743085d4782c692e64b9eae2401faee6b50bcebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Mon, 13 Feb 2023 17:47:02 +0800 Subject: [PATCH 34/44] Remove unnecessary changes and add tests. --- CMakeLists.txt | 6 -- common/output_stream.cpp | 87 ++++++++++++++-- spirv_reflect.c | 93 +++++++++-------- spirv_reflect.h | 12 ++- tests/test-spirv-reflect.cpp | 195 ++++++++++++++++++++++++++++++++++- 5 files changed, 335 insertions(+), 58 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f96f275..f66d47ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,9 +105,6 @@ if (SPIRV_REFLECT_BUILD_TESTS) CXX_STANDARD 11) target_compile_definitions(test-spirv-reflect PRIVATE $<$:_CRT_SECURE_NO_WARNINGS>) - if (SPIRV_REFLECT_ENABLE_ASSERTS) - target_compile_definitions(test-spirv-reflect PRIVATE SPIRV_REFLECT_ENABLE_ASSERTS) - endif() if(SPIRV_REFLECT_ENABLE_EVALUATION) target_compile_definitions(test-spirv-reflect PRIVATE SPIRV_REFLECT_ENABLE_CONSTANT_EVALUATION=1) endif() @@ -121,9 +118,6 @@ endif() if(SPIRV_REFLECT_STATIC_LIB) add_library(spirv-reflect-static STATIC ${CMAKE_CURRENT_SOURCE_DIR}/spirv_reflect.h ${CMAKE_CURRENT_SOURCE_DIR}/spirv_reflect.c) - if (SPIRV_REFLECT_ENABLE_ASSERTS) - target_compile_definitions(spirv-reflect-static PRIVATE SPIRV_REFLECT_ENABLE_ASSERTS) - endif() if(SPIRV_REFLECT_ENABLE_EVALUATION) target_compile_definitions(spirv-reflect-static PRIVATE SPIRV_REFLECT_ENABLE_CONSTANT_EVALUATION=1) endif() diff --git a/common/output_stream.cpp b/common/output_stream.cpp index 6e92573c..d5e5ad9f 100644 --- a/common/output_stream.cpp +++ b/common/output_stream.cpp @@ -882,6 +882,7 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth, const std::string& parent_name, uint32_t member_count, const SpvReflectBlockVariable* p_members, + SpvReflectEvaluation* evaluator, std::vector* p_text_lines) { const char* t = indent; for (uint32_t member_index = 0; member_index < member_count; ++member_index) { @@ -927,7 +928,7 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth, flatten_cbuffers ? p_text_lines : &tl.lines; ParseBlockMembersToTextLines(t, indent_depth + 1, flatten_cbuffers, current_parent_name, member.member_count, - member.members, p_target_text_line); + member.members, evaluator, p_target_text_line); tl.text_line_flags = TEXT_LINE_TYPE_LINES; p_text_lines->push_back(tl); @@ -995,7 +996,7 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth, uint32_t dim = member.array.dims[array_dim_index]; if (dim == 0xFFFFFFFF) { const SpvReflectValue* val; - SpvReflectResult res = obj.EvaluateResult(member.array.spec_constant_op_ids[array_dim_index], &val); + SpvReflectResult res = spvReflectEvaluateResult(evaluator, member.array.spec_constant_op_ids[array_dim_index], &val); if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { dim = val->data.numeric.scalar.value.uint32_bool_value; } @@ -1017,6 +1018,7 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth, void ParseBlockVariableToTextLines(const char* indent, bool flatten_cbuffers, const SpvReflectBlockVariable& block_var, + SpvReflectEvaluation* evaluator, std::vector* p_text_lines) { // Begin block TextLine tl = {}; @@ -1033,7 +1035,7 @@ void ParseBlockVariableToTextLines(const char* indent, bool flatten_cbuffers, tl = {}; ParseBlockMembersToTextLines(indent, 2, flatten_cbuffers, "", block_var.member_count, block_var.members, - &tl.lines); + evaluator, &tl.lines); tl.text_line_flags = TEXT_LINE_TYPE_LINES; p_text_lines->push_back(tl); @@ -1248,6 +1250,7 @@ void StreamWriteTextLines(std::ostream& os, const char* indent, void StreamWritePushConstantsBlock(std::ostream& os, const SpvReflectBlockVariable& obj, + SpvReflectEvaluation* evaluator, bool flatten_cbuffers, const char* indent) { const char* t = indent; os << t << "spirv id : " << obj.spirv_id << "\n"; @@ -1260,7 +1263,8 @@ void StreamWritePushConstantsBlock(std::ostream& os, } std::vector text_lines; - ParseBlockVariableToTextLines(" ", flatten_cbuffers, obj, &text_lines); + ParseBlockVariableToTextLines(" ", flatten_cbuffers, obj, evaluator, + &text_lines); if (!text_lines.empty()) { os << "\n"; StreamWriteTextLines(os, t, flatten_cbuffers, text_lines); @@ -1270,6 +1274,7 @@ void StreamWritePushConstantsBlock(std::ostream& os, void StreamWriteDescriptorBinding(std::ostream& os, const SpvReflectDescriptorBinding& obj, + SpvReflectEvaluation* evaluator, bool write_set, bool flatten_cbuffers, const char* indent) { const char* t = indent; @@ -1321,7 +1326,7 @@ void StreamWriteDescriptorBinding(std::ostream& os, obj.descriptor_type == SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER) { std::vector text_lines; ParseBlockVariableToTextLines(" ", flatten_cbuffers, obj.block, - &text_lines); + evaluator, &text_lines); if (!text_lines.empty()) { os << "\n"; StreamWriteTextLines(os, t, flatten_cbuffers, text_lines); @@ -1374,6 +1379,68 @@ void StreamWriteInterfaceVariable(std::ostream& os, } } +void StreamWriteSpecializationConstant( + std::ostream& os, const SpvReflectSpecializationConstant& obj, + const char* indent) { + const char* t = indent; + os << t << "spirv id : " << obj.spirv_id << "\n"; + os << t << "constant id: " << obj.constant_id << "\n"; + os << t << "name : " << (obj.name != NULL ? obj.name : "") << '\n'; + os << t << "type : "; + int type = 0; + if (!obj.type || obj.type->type_flags == SPV_REFLECT_TYPE_FLAG_BOOL) { + type = 1; + } else if (obj.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) { + type = 2; + } else if (obj.type->type_flags == SPV_REFLECT_TYPE_FLAG_FLOAT) { + type = 3; + } + switch (type) { + case 1: + os << "boolean\n"; + os << t << "default : " << obj.default_value.value.uint32_bool_value; + break; + case 2: + if (obj.type->traits.numeric.scalar.signedness) { + os << "signed "; + } else { + os << "unsigned "; + } + os << obj.type->traits.numeric.scalar.width << " bit integer\n"; + os << t << "default : "; + // let's assume only 32 bit and 64 bit types (no 8 and 16 bit types here) + if (obj.type->traits.numeric.scalar.width == 32) { + if (obj.type->traits.numeric.scalar.signedness) { + os << obj.default_value.value.sint32_value; + } else { + os << obj.default_value.value.uint32_bool_value; + } + } else if (obj.type->traits.numeric.scalar.width == 64) { + if (obj.type->traits.numeric.scalar.signedness) { + os << obj.default_value.value.sint64_value; + } else { + os << obj.default_value.value.uint64_value; + } + } else { + os << "default value not native in c/cpp"; + } + break; + case 3: + os << obj.type->traits.numeric.scalar.width << " bit floating point\n"; + os << t << "default : "; + if (obj.type->traits.numeric.scalar.width == 32) { + os << obj.default_value.value.float32_value; + } else if (obj.type->traits.numeric.scalar.width == 64) { + os << obj.default_value.value.float64_value; + } else { + os << "default value not native in c/cpp"; + } + break; + default: + os << "unknown type"; + } +} + void StreamWriteEntryPoint(std::ostream& os, const SpvReflectEntryPoint& obj, const char* indent) { os << indent << "entry point : " << obj.name; @@ -1400,7 +1467,7 @@ void StreamWriteShaderModule(std::ostream& os, // "\n"; for (uint32_t i = 0; i < obj.entry_point_count; ++i) { - StreamWriteEntryPoint(os, eval, obj.entry_points[i], ""); + StreamWriteEntryPoint(os, obj.entry_points[i], ""); if (i < (obj.entry_point_count - 1)) { os << "\n"; } @@ -1420,7 +1487,7 @@ void WriteReflection(const spv_reflect::ShaderModule& obj, const char* tt = " "; const char* ttt = " "; - StreamWriteShaderModule(os, obj.GetShaderModule(), obj.GetEvaluation(), ""); + StreamWriteShaderModule(os, obj.GetShaderModule(), ""); uint32_t count = 0; std::vector variables; @@ -1512,7 +1579,8 @@ void WriteReflection(const spv_reflect::ShaderModule& obj, auto p_block = push_constant_bocks[i]; os << tt << i << ":" << "\n"; - StreamWritePushConstantsBlock(os, *p_block, flatten_cbuffers, ttt); + StreamWritePushConstantsBlock(os, *p_block, obj.GetEvaluationInterface(), + flatten_cbuffers, ttt); } } @@ -1541,7 +1609,8 @@ void WriteReflection(const spv_reflect::ShaderModule& obj, os << tt << "Binding" << " " << p_binding->set << "." << p_binding->binding << "" << "\n"; - StreamWriteDescriptorBinding(os, *p_binding, true, flatten_cbuffers, ttt); + StreamWriteDescriptorBinding(os, *p_binding, obj.GetEvaluationInterface(), + true, flatten_cbuffers, ttt); if (i < (count - 1)) { os << "\n\n"; } diff --git a/spirv_reflect.c b/spirv_reflect.c index 2f2a04a2..ba38acc9 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -309,7 +309,7 @@ static uint32_t RoundUp( uint32_t value, uint32_t multiple) { - SPV_REFLECT_ASSERT(multiple && ((multiple & (multiple - 1)) == 0)); + assert(multiple && ((multiple & (multiple - 1)) == 0)); return (value + multiple - 1) & ~(multiple - 1); } @@ -445,13 +445,13 @@ static bool InRange( } static SpvReflectResult ReadU32( - const SpvReflectPrvParser* p_parser, + SpvReflectPrvParser* p_parser, uint32_t word_offset, uint32_t* p_value) { - SPV_REFLECT_ASSERT(IsNotNull(p_parser)); - SPV_REFLECT_ASSERT(IsNotNull(p_parser->spirv_code)); - SPV_REFLECT_ASSERT(InRange(p_parser, word_offset)); + assert(IsNotNull(p_parser)); + assert(IsNotNull(p_parser->spirv_code)); + assert(InRange(p_parser, word_offset)); SpvReflectResult result = SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_EOF; if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && InRange(p_parser, word_offset)) { *p_value = *(p_parser->spirv_code + word_offset); @@ -505,9 +505,9 @@ static SpvReflectResult ReadStr( ) { uint32_t limit = (word_offset + word_count); - SPV_REFLECT_ASSERT(IsNotNull(p_parser)); - SPV_REFLECT_ASSERT(IsNotNull(p_parser->spirv_code)); - SPV_REFLECT_ASSERT(InRange(p_parser, limit)); + assert(IsNotNull(p_parser)); + assert(IsNotNull(p_parser->spirv_code)); + assert(InRange(p_parser, limit)); SpvReflectResult result = SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_EOF; if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && InRange(p_parser, limit)) { const char* c_str = (const char*)(p_parser->spirv_code + word_offset + word_index); @@ -589,7 +589,7 @@ static void ApplyArrayTraits(const SpvReflectTypeDescription* p_type, SpvReflect } static SpvReflectPrvNode* FindNode( - const SpvReflectPrvParser* p_parser, + SpvReflectPrvParser* p_parser, uint32_t result_id) { SpvReflectPrvNode* p_node = NULL; @@ -633,6 +633,7 @@ static SpvReflectPrvEvaluationNode* FindSpecIdNode( return p_node; } +// const required for evaluation calls that need type info static SpvReflectTypeDescription* FindType(const SpvReflectShaderModule* p_module, uint32_t type_id) { SpvReflectTypeDescription* p_type = NULL; @@ -709,8 +710,8 @@ static void DestroyParser(SpvReflectPrvParser* p_parser) static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) { - SPV_REFLECT_ASSERT(IsNotNull(p_parser)); - SPV_REFLECT_ASSERT(IsNotNull(p_parser->spirv_code)); + assert(IsNotNull(p_parser)); + assert(IsNotNull(p_parser->spirv_code)); uint32_t* p_spirv = p_parser->spirv_code; uint32_t spirv_word_index = SPIRV_STARTING_WORD_INDEX; @@ -998,7 +999,7 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) // Read index value uint32_t index_value = UINT32_MAX; CHECKED_READU32(p_parser, p_index_value_node->word_offset + 3, index_value); - SPV_REFLECT_ASSERT(index_value != UINT32_MAX); + assert(index_value != UINT32_MAX); // Write index value to array p_access_chain->indexes[index_index] = index_value; } @@ -1049,9 +1050,9 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) static SpvReflectResult ParseStrings(SpvReflectPrvParser* p_parser) { - SPV_REFLECT_ASSERT(IsNotNull(p_parser)); - SPV_REFLECT_ASSERT(IsNotNull(p_parser->spirv_code)); - SPV_REFLECT_ASSERT(IsNotNull(p_parser->nodes)); + assert(IsNotNull(p_parser)); + assert(IsNotNull(p_parser->spirv_code)); + assert(IsNotNull(p_parser->nodes)); // Early out if (p_parser->string_count == 0) { @@ -1072,7 +1073,7 @@ static SpvReflectResult ParseStrings(SpvReflectPrvParser* p_parser) } // Paranoid check against string count - SPV_REFLECT_ASSERT(string_index < p_parser->string_count); + assert(string_index < p_parser->string_count); if (string_index >= p_parser->string_count) { return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH; } @@ -1095,8 +1096,8 @@ static SpvReflectResult ParseStrings(SpvReflectPrvParser* p_parser) static SpvReflectResult ParseSource(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) { - SPV_REFLECT_ASSERT(IsNotNull(p_parser)); - SPV_REFLECT_ASSERT(IsNotNull(p_parser->spirv_code)); + assert(IsNotNull(p_parser)); + assert(IsNotNull(p_parser->spirv_code)); if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code)) { // Source file @@ -1271,9 +1272,9 @@ static int SortCompareFunctions( static SpvReflectResult ParseFunctions(SpvReflectPrvParser* p_parser) { - SPV_REFLECT_ASSERT(IsNotNull(p_parser)); - SPV_REFLECT_ASSERT(IsNotNull(p_parser->spirv_code)); - SPV_REFLECT_ASSERT(IsNotNull(p_parser->nodes)); + assert(IsNotNull(p_parser)); + assert(IsNotNull(p_parser->spirv_code)); + assert(IsNotNull(p_parser->nodes)); if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) { if (p_parser->function_count == 0) { @@ -1353,9 +1354,9 @@ static SpvReflectResult ParseFunctions(SpvReflectPrvParser* p_parser) static SpvReflectResult ParseMemberCounts(SpvReflectPrvParser* p_parser) { - SPV_REFLECT_ASSERT(IsNotNull(p_parser)); - SPV_REFLECT_ASSERT(IsNotNull(p_parser->spirv_code)); - SPV_REFLECT_ASSERT(IsNotNull(p_parser->nodes)); + assert(IsNotNull(p_parser)); + assert(IsNotNull(p_parser->spirv_code)); + assert(IsNotNull(p_parser->nodes)); if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) { for (size_t i = 0; i < p_parser->node_count; ++i) { @@ -1403,9 +1404,9 @@ static SpvReflectResult ParseMemberCounts(SpvReflectPrvParser* p_parser) static SpvReflectResult ParseNames(SpvReflectPrvParser* p_parser) { - SPV_REFLECT_ASSERT(IsNotNull(p_parser)); - SPV_REFLECT_ASSERT(IsNotNull(p_parser->spirv_code)); - SPV_REFLECT_ASSERT(IsNotNull(p_parser->nodes)); + assert(IsNotNull(p_parser)); + assert(IsNotNull(p_parser->spirv_code)); + assert(IsNotNull(p_parser->nodes)); if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) { for (size_t i = 0; i < p_parser->node_count; ++i) { @@ -1914,7 +1915,7 @@ static SpvReflectResult ParseType( // Member decorations SpvReflectPrvDecorations* p_member_decorations = &p_node->member_decorations[member_index]; - SPV_REFLECT_ASSERT(member_index < p_type->member_count); + assert(member_index < p_type->member_count); // Parse member type SpvReflectTypeDescription* p_member_type = &(p_type->members[member_index]); p_member_type->id = member_id; @@ -2052,7 +2053,7 @@ static int SortCompareDescriptorBinding(const void* a, const void* b) if (value == 0) { // use spirv-id as a tiebreaker to ensure a stable ordering, as they're guaranteed // unique. - SPV_REFLECT_ASSERT(p_elem_a->spirv_id != p_elem_b->spirv_id); + assert(p_elem_a->spirv_id != p_elem_b->spirv_id); value = (int)(p_elem_a->spirv_id) - (int)(p_elem_b->spirv_id); } return value; @@ -2210,12 +2211,12 @@ static SpvReflectResult ParseDescriptorType(SpvReflectShaderModule* p_module) if ((int)p_descriptor->descriptor_type == (int)INVALID_VALUE) { switch (p_type->type_flags & SPV_REFLECT_TYPE_FLAG_EXTERNAL_MASK) { - default: SPV_REFLECT_ASSERT(false && "unknown type flag"); break; + default: assert(false && "unknown type flag"); break; case SPV_REFLECT_TYPE_FLAG_EXTERNAL_IMAGE: { if (p_descriptor->image.dim == SpvDimBuffer) { switch (p_descriptor->image.sampled) { - default: SPV_REFLECT_ASSERT(false && "unknown texel buffer sampled value"); break; + default: assert(false && "unknown texel buffer sampled value"); break; case IMAGE_SAMPLED: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; break; case IMAGE_STORAGE: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; break; } @@ -2225,7 +2226,7 @@ static SpvReflectResult ParseDescriptorType(SpvReflectShaderModule* p_module) } else { switch (p_descriptor->image.sampled) { - default: SPV_REFLECT_ASSERT(false && "unknown image sampled value"); break; + default: assert(false && "unknown image sampled value"); break; case IMAGE_SAMPLED: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE; break; case IMAGE_STORAGE: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE; break; } @@ -2242,7 +2243,7 @@ static SpvReflectResult ParseDescriptorType(SpvReflectShaderModule* p_module) // This is a workaround for: https://github.com/KhronosGroup/glslang/issues/1096 if (p_descriptor->image.dim == SpvDimBuffer) { switch (p_descriptor->image.sampled) { - default: SPV_REFLECT_ASSERT(false && "unknown texel buffer sampled value"); break; + default: assert(false && "unknown texel buffer sampled value"); break; case IMAGE_SAMPLED: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; break; case IMAGE_STORAGE: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; break; } @@ -2261,7 +2262,7 @@ static SpvReflectResult ParseDescriptorType(SpvReflectShaderModule* p_module) p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER; } else { - SPV_REFLECT_ASSERT(false && "unknown struct"); + assert(false && "unknown struct"); } } break; @@ -2656,7 +2657,7 @@ static SpvReflectResult ParseDescriptorBlockVariableUsage( break; case SpvOpTypeStruct: { - SPV_REFLECT_ASSERT(p_var->member_count > 0); + assert(p_var->member_count > 0); if (p_var->member_count == 0) { return SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_BLOCK_DATA; } @@ -3370,9 +3371,9 @@ static SpvReflectResult ParseExecutionModes( SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) { - SPV_REFLECT_ASSERT(IsNotNull(p_parser)); - SPV_REFLECT_ASSERT(IsNotNull(p_parser->nodes)); - SPV_REFLECT_ASSERT(IsNotNull(p_module)); + assert(IsNotNull(p_parser)); + assert(IsNotNull(p_parser->nodes)); + assert(IsNotNull(p_module)); if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) { for (size_t node_idx = 0; node_idx < p_parser->node_count; ++node_idx) { @@ -3906,7 +3907,7 @@ static int SortCompareDescriptorSet(const void* a, const void* b) int value = (int)(p_elem_a->set) - (int)(p_elem_b->set); // We should never see duplicate descriptor set numbers in a shader; if so, a tiebreaker // would be needed here. - SPV_REFLECT_ASSERT(value != 0); + assert(value != 0); return value; } @@ -4042,7 +4043,7 @@ static SpvReflectResult ParseDescriptorSets(SpvReflectShaderModule* p_module) for (uint32_t j = 0; j < p_module->descriptor_binding_count; ++j) { SpvReflectDescriptorBinding* p_descriptor = &(p_module->descriptor_bindings[j]); if (p_descriptor->set == p_set->set) { - SPV_REFLECT_ASSERT(descriptor_index < p_set->binding_count); + assert(descriptor_index < p_set->binding_count); p_set->bindings[descriptor_index] = p_descriptor; ++descriptor_index; } @@ -7509,7 +7510,6 @@ SpvReflectResult spvReflectGetSpecializationInfo(const SpvReflectEvaluation* p_e for (uint32_t i = 0; i < p_eval->member_type_finder->specialization_constant_count && count < num_entries; ++i) { SpvReflectPrvEvaluationNode* p_node = FindSpecIdNode(p_eval, p_eval->member_type_finder->specialization_constants[i].constant_id); if (p_node->specialized) { - ++count; p_modifiable[count].constantID = p_node->specId; p_modifiable[count].size = p_node->value.type->traits.numeric.scalar.width / 8; // VUID-VkSpecializationMapEntry-constantID-00776 @@ -7528,12 +7528,18 @@ SpvReflectResult spvReflectGetSpecializationInfo(const SpvReflectEvaluation* p_e if(idx < first_element){ first_element = idx; } + ++count; } } info->mapEntryCount = count; if(count){ info->pData = ((uint8_t*)(p_eval->nodes + first_element)) + offsetof(SpvReflectPrvEvaluationNode, value.data.numeric.scalar.value); + for (uint32_t i = 0; i < count; ++i) { + p_modifiable[i].offset -= + first_element * sizeof(SpvReflectPrvEvaluationNode); + } info->dataSize = sizeof(SpvReflectPrvEvaluationNode) * (last_element - first_element) + last_element_size; + info->pMapEntries = p_modifiable; } } return SPV_REFLECT_RESULT_SUCCESS; @@ -7570,6 +7576,9 @@ SpvReflectEvaluation* spvReflectDuplicateEvaluation(const SpvReflectEvaluation* memcpy(p_copied->nodes, p_eval->nodes, p_eval->node_count*sizeof(SpvReflectPrvEvaluationNode)); for (uint32_t i = 0; i < p_eval->node_count; ++i) { SPV_REFLECT_ASSERT(p_copied->nodes[i].num_id_operands == p_eval->nodes[i].num_id_operands); + p_copied->nodes[i].id_operands = + p_copied->id_operands + + (p_eval->nodes[i].id_operands - p_eval->id_operands); for (uint32_t j = 0; j < p_eval->nodes[i].num_id_operands; ++j) { p_copied->nodes[i].id_operands[j] = &p_copied->nodes[p_eval->nodes[i].id_operands[j] - p_eval->nodes]; } @@ -7596,6 +7605,8 @@ SpvReflectEvaluation* spvReflectDuplicateEvaluation(const SpvReflectEvaluation* } } + p_copied->member_type_finder = p_eval->member_type_finder; + return p_copied; CLEANUP: diff --git a/spirv_reflect.h b/spirv_reflect.h index 6ed61924..6e54ead4 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -550,7 +550,12 @@ typedef struct SpvReflectCapability { } SpvReflectCapability; /*! @struct SpvReflectEvaluation - @brief Opaque type that stores evaluation state and information + @brief Opaque type that stores evaluation state and information. + There are two types of evaluator: the one that is parsed from + spv code, and the duplicated instances that can have different + spec-constant specified. Duplicated ones need to be freed manually. + Freeing the original one does nothing. Type info is stored in + shader module struct reference, and thus have to have a longer lifetime. */ typedef struct SpvReflectEvaluation SpvReflectEvaluation; @@ -1770,6 +1775,11 @@ class ShaderModule { SpvReflectResult ChangeInputVariableLocation(const SpvReflectInterfaceVariable* p_input_variable, uint32_t new_location); SpvReflectResult ChangeOutputVariableLocation(const SpvReflectInterfaceVariable* p_output_variable, uint32_t new_location); + SpvReflectEvaluation* GetEvaluationInterface() const + { + return spvReflectGetEvaluationInterface(&m_module); + } + private: // Make noncopyable ShaderModule(const ShaderModule&); diff --git a/tests/test-spirv-reflect.cpp b/tests/test-spirv-reflect.cpp index 4ebd0b98..30d3301a 100644 --- a/tests/test-spirv-reflect.cpp +++ b/tests/test-spirv-reflect.cpp @@ -1455,7 +1455,6 @@ TEST(SpirvReflectSpecializationConstantTest, TestSpecParsingFloat) } #if SPIRV_REFLECT_ENABLE_CONSTANT_EVALUATION - TEST(SpirvReflectSpecializationConstantTest, TestEvaluate32) { std::vector spirv_; @@ -1649,4 +1648,198 @@ TEST(SpirvReflectSpecializationConstantTest, TestConvert) { ASSERT_EQ(res->data.numeric.scalar.value.uint32_bool_value, 1); } } + +TEST(SpirvReflectSpecializationConstantTest, TestInstancing) { + std::vector spirv_; + SpvReflectShaderModule module_; + const std::string spirv_path = "../tests/spec_constant/test_32bit.spv"; + std::ifstream spirv_file(spirv_path, std::ios::binary | std::ios::ate); + std::streampos spirv_file_nbytes = spirv_file.tellg(); + spirv_file.seekg(0); + spirv_.resize(spirv_file_nbytes); + spirv_file.read(reinterpret_cast(spirv_.data()), spirv_.size()); + + SpvReflectResult result = + spvReflectCreateShaderModule2(SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT | + SPV_REFLECT_MODULE_FLAG_NO_COPY, + spirv_.size(), spirv_.data(), &module_); + ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result) + << "spvReflectCreateShaderModule() failed"; + + EXPECT_EQ(module_.entry_point_count, 1); + EXPECT_EQ(module_.entry_points[0].shader_stage, + SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT); + EXPECT_EQ(module_.entry_points[0].local_size.flags, 4); + ASSERT_EQ(module_.specialization_constant_count, 9); + SpvReflectEvaluation* p_eval_orig = + spvReflectGetEvaluationInterface(&module_); + ASSERT_NE(p_eval_orig, nullptr); + + SpvReflectEvaluation* p_eval = spvReflectDuplicateEvaluation(p_eval_orig); + + const SpvReflectValue* res = nullptr; + + SpvReflectScalarValueData data = {0}; + data.value.sint32_value = -2; + ASSERT_EQ(spvReflectSetSpecConstantValue( + p_eval_orig, 7, SPIRV_REFLECT_SCALAR_TYPE_I32, &data), + SPV_REFLECT_RESULT_SUCCESS); + SpvReflectTypeDescription* p_type = + module_.descriptor_bindings[10].type_description; + SpvReflectTypeDescription* p_type_arr = &p_type->members[0]; + res = nullptr; + ASSERT_EQ( + spvReflectEvaluateResult( + p_eval_orig, p_type_arr->traits.array.spec_constant_op_ids[0], &res), + SPV_REFLECT_RESULT_SUCCESS); + ASSERT_NE(res, nullptr); + ASSERT_NE(res->type, nullptr); + ASSERT_EQ(res->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + ASSERT_EQ(res->type->traits.numeric.scalar.width, 32); + ASSERT_EQ(res->data.numeric.scalar.value.sint32_value, 2); + + res = nullptr; + ASSERT_EQ(spvReflectEvaluateResult( + p_eval, p_type_arr->traits.array.spec_constant_op_ids[0], &res), + SPV_REFLECT_RESULT_SUCCESS); + ASSERT_NE(res, nullptr); + ASSERT_NE(res->type, nullptr); + ASSERT_EQ(res->type->type_flags, SPV_REFLECT_TYPE_FLAG_INT); + ASSERT_EQ(res->type->traits.numeric.scalar.width, 32); + ASSERT_EQ(res->data.numeric.scalar.value.sint32_value, 1); + + spvReflectDestroyDuplicatedEvaluation(p_eval); + spvReflectDestroyShaderModule(&module_); +} + +TEST(SpirvReflectSpecializationConstantTest, TestRelations) { + std::vector spirv_; + SpvReflectShaderModule module_; + const std::string spirv_path = "../tests/spec_constant/test_32bit.spv"; + std::ifstream spirv_file(spirv_path, std::ios::binary | std::ios::ate); + std::streampos spirv_file_nbytes = spirv_file.tellg(); + spirv_file.seekg(0); + spirv_.resize(spirv_file_nbytes); + spirv_file.read(reinterpret_cast(spirv_.data()), spirv_.size()); + + SpvReflectResult result = + spvReflectCreateShaderModule2(SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT | + SPV_REFLECT_MODULE_FLAG_NO_COPY, + spirv_.size(), spirv_.data(), &module_); + ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result) + << "spvReflectCreateShaderModule() failed"; + + EXPECT_EQ(module_.entry_point_count, 1); + EXPECT_EQ(module_.entry_points[0].shader_stage, + SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT); + EXPECT_EQ(module_.entry_points[0].local_size.flags, 4); + ASSERT_EQ(module_.specialization_constant_count, 9); + SpvReflectEvaluation* p_eval = spvReflectGetEvaluationInterface(&module_); + ASSERT_NE(p_eval, nullptr); + SpvReflectTypeDescription* p_type = + module_.descriptor_bindings[10].type_description; + SpvReflectTypeDescription* p_type_arr = &p_type->members[0]; + + + ASSERT_EQ(spvReflectIsRelatedToSpecId( + p_eval, p_type_arr->traits.array.spec_constant_op_ids[0], 0), + 0); + ASSERT_EQ(spvReflectIsRelatedToSpecId( + p_eval, p_type_arr->traits.array.spec_constant_op_ids[0], 1), + 0); + ASSERT_EQ(spvReflectIsRelatedToSpecId( + p_eval, p_type_arr->traits.array.spec_constant_op_ids[0], 2), + 1); + ASSERT_EQ(spvReflectIsRelatedToSpecId( + p_eval, p_type_arr->traits.array.spec_constant_op_ids[0], 3), + 1); + ASSERT_EQ(spvReflectIsRelatedToSpecId( + p_eval, p_type_arr->traits.array.spec_constant_op_ids[0], 4), + 0); + ASSERT_EQ(spvReflectIsRelatedToSpecId( + p_eval, p_type_arr->traits.array.spec_constant_op_ids[0], 5), + 1); + ASSERT_EQ(spvReflectIsRelatedToSpecId( + p_eval, p_type_arr->traits.array.spec_constant_op_ids[0], 6), + 1); + ASSERT_EQ(spvReflectIsRelatedToSpecId( + p_eval, p_type_arr->traits.array.spec_constant_op_ids[0], 7), + 1); + + spvReflectDestroyShaderModule(&module_); +} + +#if _SPIRV_REFLECT_USE_VULKAN_H_ +#include +#else +// Provided by VK_VERSION_1_0 +typedef struct VkSpecializationInfo { + uint32_t mapEntryCount; + const VkSpecializationMapEntry* pMapEntries; + size_t dataSize; + const void* pData; +} VkSpecializationInfo; +// Provided by VK_VERSION_1_0 +typedef struct VkSpecializationMapEntry { + uint32_t constantID; + uint32_t offset; + size_t size; +} VkSpecializationMapEntry; +#endif + +TEST(SpirvReflectSpecializationConstantTest, TestMapEntry) { + std::vector spirv_; + SpvReflectShaderModule module_; + const std::string spirv_path = "../tests/spec_constant/test_32bit.spv"; + std::ifstream spirv_file(spirv_path, std::ios::binary | std::ios::ate); + std::streampos spirv_file_nbytes = spirv_file.tellg(); + spirv_file.seekg(0); + spirv_.resize(spirv_file_nbytes); + spirv_file.read(reinterpret_cast(spirv_.data()), spirv_.size()); + + SpvReflectResult result = + spvReflectCreateShaderModule2(SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT | + SPV_REFLECT_MODULE_FLAG_NO_COPY, + spirv_.size(), spirv_.data(), &module_); + ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result) + << "spvReflectCreateShaderModule() failed"; + + EXPECT_EQ(module_.entry_point_count, 1); + EXPECT_EQ(module_.entry_points[0].shader_stage, + SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT); + EXPECT_EQ(module_.entry_points[0].local_size.flags, 4); + ASSERT_EQ(module_.specialization_constant_count, 9); + SpvReflectEvaluation* p_eval = spvReflectGetEvaluationInterface(&module_); + ASSERT_NE(p_eval, nullptr); + SpvReflectTypeDescription* p_type = + module_.descriptor_bindings[10].type_description; + SpvReflectTypeDescription* p_type_arr = &p_type->members[0]; + + VkSpecializationInfo info; + ASSERT_EQ(spvReflectGetSpecializationInfo(p_eval, &info, NULL, 0), SPV_REFLECT_RESULT_SUCCESS); + std::vector entries(info.mapEntryCount); + ASSERT_EQ(info.mapEntryCount, 0); + ASSERT_EQ(spvReflectGetSpecializationInfo(p_eval, &info, entries.data(), + info.mapEntryCount), + SPV_REFLECT_RESULT_SUCCESS); + SpvReflectScalarValueData data = {0}; + data.value.sint32_value = -2; + ASSERT_EQ(spvReflectSetSpecConstantValue( + p_eval, 7, SPIRV_REFLECT_SCALAR_TYPE_I32, &data), + SPV_REFLECT_RESULT_SUCCESS); + ASSERT_EQ(spvReflectGetSpecializationInfo(p_eval, &info, NULL, 0), + SPV_REFLECT_RESULT_SUCCESS); + ASSERT_EQ(info.mapEntryCount, 1); + entries.resize(info.mapEntryCount); + ASSERT_EQ(spvReflectGetSpecializationInfo(p_eval, &info, entries.data(), + info.mapEntryCount), + SPV_REFLECT_RESULT_SUCCESS); + ASSERT_EQ(info.dataSize, 4); + ASSERT_EQ(info.pMapEntries[0].constantID, 7); + ASSERT_EQ(info.pMapEntries[0].offset, 0); + ASSERT_EQ(info.pMapEntries[0].size, 4); + ASSERT_EQ(*((int*)info.pData), -2); + spvReflectDestroyShaderModule(&module_); +} + #endif From 4fdf0625fef3f8b015a3517d04af856e14ec840c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sat, 20 May 2023 01:04:44 +0800 Subject: [PATCH 35/44] Clean up for merge Updated `SpvReflectEntryPoint` to have non-conflicting struct alignment. Formatting fix. --- common/output_stream.cpp | 93 ++++++++++++++++++----- spirv_reflect.c | 31 ++++++-- spirv_reflect.h | 154 +++++++++++++++++---------------------- 3 files changed, 165 insertions(+), 113 deletions(-) diff --git a/common/output_stream.cpp b/common/output_stream.cpp index d5e5ad9f..c45fb982 100644 --- a/common/output_stream.cpp +++ b/common/output_stream.cpp @@ -882,7 +882,7 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth, const std::string& parent_name, uint32_t member_count, const SpvReflectBlockVariable* p_members, - SpvReflectEvaluation* evaluator, + SpvReflectEvaluation* p_evaluator, std::vector* p_text_lines) { const char* t = indent; for (uint32_t member_index = 0; member_index < member_count; ++member_index) { @@ -928,7 +928,7 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth, flatten_cbuffers ? p_text_lines : &tl.lines; ParseBlockMembersToTextLines(t, indent_depth + 1, flatten_cbuffers, current_parent_name, member.member_count, - member.members, evaluator, p_target_text_line); + member.members, p_evaluator, p_target_text_line); tl.text_line_flags = TEXT_LINE_TYPE_LINES; p_text_lines->push_back(tl); @@ -958,6 +958,13 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth, // dim = 0 means it's an unbounded array // if (dim > 0) { + if (dim == 0xFFFFFFFF) { + const SpvReflectValue* val; + SpvReflectResult res = spvReflectEvaluateResult(p_evaluator, member.array.spec_constant_op_ids[array_dim_index], &val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { + dim = val->data.numeric.scalar.value.uint32_bool_value; + } + } ss_array << "[" << dim << "]"; } else { ss_array << "[]"; @@ -996,7 +1003,7 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth, uint32_t dim = member.array.dims[array_dim_index]; if (dim == 0xFFFFFFFF) { const SpvReflectValue* val; - SpvReflectResult res = spvReflectEvaluateResult(evaluator, member.array.spec_constant_op_ids[array_dim_index], &val); + SpvReflectResult res = spvReflectEvaluateResult(p_evaluator, member.array.spec_constant_op_ids[array_dim_index], &val); if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { dim = val->data.numeric.scalar.value.uint32_bool_value; } @@ -1018,7 +1025,7 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth, void ParseBlockVariableToTextLines(const char* indent, bool flatten_cbuffers, const SpvReflectBlockVariable& block_var, - SpvReflectEvaluation* evaluator, + SpvReflectEvaluation* p_evaluator, std::vector* p_text_lines) { // Begin block TextLine tl = {}; @@ -1035,7 +1042,7 @@ void ParseBlockVariableToTextLines(const char* indent, bool flatten_cbuffers, tl = {}; ParseBlockMembersToTextLines(indent, 2, flatten_cbuffers, "", block_var.member_count, block_var.members, - evaluator, &tl.lines); + p_evaluator, &tl.lines); tl.text_line_flags = TEXT_LINE_TYPE_LINES; p_text_lines->push_back(tl); @@ -1250,7 +1257,7 @@ void StreamWriteTextLines(std::ostream& os, const char* indent, void StreamWritePushConstantsBlock(std::ostream& os, const SpvReflectBlockVariable& obj, - SpvReflectEvaluation* evaluator, + SpvReflectEvaluation* p_evaluator, bool flatten_cbuffers, const char* indent) { const char* t = indent; os << t << "spirv id : " << obj.spirv_id << "\n"; @@ -1263,7 +1270,7 @@ void StreamWritePushConstantsBlock(std::ostream& os, } std::vector text_lines; - ParseBlockVariableToTextLines(" ", flatten_cbuffers, obj, evaluator, + ParseBlockVariableToTextLines(" ", flatten_cbuffers, obj, p_evaluator, &text_lines); if (!text_lines.empty()) { os << "\n"; @@ -1274,7 +1281,7 @@ void StreamWritePushConstantsBlock(std::ostream& os, void StreamWriteDescriptorBinding(std::ostream& os, const SpvReflectDescriptorBinding& obj, - SpvReflectEvaluation* evaluator, + SpvReflectEvaluation* p_evaluator, bool write_set, bool flatten_cbuffers, const char* indent) { const char* t = indent; @@ -1326,7 +1333,7 @@ void StreamWriteDescriptorBinding(std::ostream& os, obj.descriptor_type == SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER) { std::vector text_lines; ParseBlockVariableToTextLines(" ", flatten_cbuffers, obj.block, - evaluator, &text_lines); + p_evaluator, &text_lines); if (!text_lines.empty()) { os << "\n"; StreamWriteTextLines(os, t, flatten_cbuffers, text_lines); @@ -1441,21 +1448,66 @@ void StreamWriteSpecializationConstant( } } -void StreamWriteEntryPoint(std::ostream& os, const SpvReflectEntryPoint& obj, - const char* indent) { +void StreamWriteEntryPoint(std::ostream& os, SpvReflectEvaluation* p_eval, const SpvReflectEntryPoint& obj, int entry_flag, const char* indent) +{ os << indent << "entry point : " << obj.name; os << " (stage=" << ToStringShaderStage(obj.shader_stage) << ")"; if (obj.shader_stage == SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT) { os << "\n"; - os << "local size : " - << "(" << obj.local_size.x << ", " << obj.local_size.y << ", " - << obj.local_size.z << ")"; + if (entry_flag & 2) { + os << "local size : "; + } + else { + os << "local size hint : "; + } + if (entry_flag & 4) { + const SpvReflectValue* val; + SpvReflectResult res = spvReflectEvaluateResult(p_eval, obj.local_size.x, &val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == (SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_VECTOR)) + && (val->type->traits.numeric.scalar.width == 32)) { + os << "(" << val->data.numeric.vector.value[0].value.uint32_bool_value << ", " + << val->data.numeric.vector.value[1].value.uint32_bool_value << ", " + << val->data.numeric.vector.value[2].value.uint32_bool_value << ")"; + } + else { + os << "(failed evaluation of WorkGroupSize Builtin)"; + } + } + else if(entry_flag & 1) { + os << "("; + const SpvReflectValue* val; + SpvReflectResult res = spvReflectEvaluateResult(p_eval, obj.local_size.x, &val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { + os << val->data.numeric.scalar.value.uint32_bool_value; + } + else { + os << "unknown"; + } + os << ", "; + res = spvReflectEvaluateResult(p_eval, obj.local_size.y, &val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { + os << val->data.numeric.scalar.value.uint32_bool_value; + } + else { + os << "unknown"; + } os << ", "; + res = spvReflectEvaluateResult(p_eval, obj.local_size.z, &val); + if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) { + os << val->data.numeric.vector.value[2].value.uint32_bool_value; + } + else { + os << "unknown"; + } + os << ")"; + } + else{ + os << "(" << obj.local_size.x << ", " << obj.local_size.y << ", " << obj.local_size.z << ")"; + } } } -void StreamWriteShaderModule(std::ostream& os, - const SpvReflectShaderModule& obj, - const char* indent) { +void StreamWriteShaderModule(std::ostream& os, const SpvReflectShaderModule& obj, SpvReflectEvaluation* p_eval,const char* indent) +{ (void)indent; os << "generator : " << ToStringGenerator(obj.generator) << "\n"; os << "source lang : " << spvReflectSourceLanguage(obj.source_language) @@ -1467,7 +1519,8 @@ void StreamWriteShaderModule(std::ostream& os, // "\n"; for (uint32_t i = 0; i < obj.entry_point_count; ++i) { - StreamWriteEntryPoint(os, obj.entry_points[i], ""); + int mode_flag = spvReflectGetEntryModeFlag(&obj, &obj.entry_points[i]); + StreamWriteEntryPoint(os, p_eval, obj.entry_points[i], mode_flag,""); if (i < (obj.entry_point_count - 1)) { os << "\n"; } @@ -1487,7 +1540,9 @@ void WriteReflection(const spv_reflect::ShaderModule& obj, const char* tt = " "; const char* ttt = " "; - StreamWriteShaderModule(os, obj.GetShaderModule(), ""); + const SpvReflectShaderModule& ref_module = obj.GetShaderModule(); + SpvReflectEvaluation* p_eval = spvReflectGetEvaluationInterface(&ref_module); + StreamWriteShaderModule(os, ref_module, p_eval, ""); uint32_t count = 0; std::vector variables; diff --git a/spirv_reflect.c b/spirv_reflect.c index ba38acc9..e2b7bcfd 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -3260,7 +3260,9 @@ static SpvReflectResult ParseEntryPoints( p_module->entry_point_count = p_parser->entry_point_count; p_module->entry_points = (SpvReflectEntryPoint*)calloc(p_module->entry_point_count, sizeof(*(p_module->entry_points))); - if (IsNull(p_module->entry_points)) { + p_module->_internal->entry_point_mode_flags = (int*)calloc(p_module->entry_point_count, + sizeof(*(p_module->_internal->entry_point_mode_flags))); + if (IsNull(p_module->entry_points) || IsNull(p_module->_internal->entry_point_mode_flags)) { return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; } @@ -3392,9 +3394,11 @@ static SpvReflectResult ParseExecutionModes( // Find entry point SpvReflectEntryPoint* p_entry_point = NULL; + int* p_entry_mode_flag = NULL; for (size_t entry_point_idx = 0; entry_point_idx < p_module->entry_point_count; ++entry_point_idx) { if (p_module->entry_points[entry_point_idx].id == entry_point_id) { p_entry_point = &p_module->entry_points[entry_point_idx]; + p_entry_mode_flag = &p_module->_internal->entry_point_mode_flags[entry_point_idx]; break; } } @@ -3441,7 +3445,7 @@ static SpvReflectResult ParseExecutionModes( break; case SpvExecutionModeLocalSize: { - p_entry_point->local_size.flags = 0; + *p_entry_mode_flag = 0; CHECKED_READU32(p_parser, p_node->word_offset + 3, p_entry_point->local_size.x); CHECKED_READU32(p_parser, p_node->word_offset + 4, p_entry_point->local_size.y); CHECKED_READU32(p_parser, p_node->word_offset + 5, p_entry_point->local_size.z); @@ -3449,7 +3453,7 @@ static SpvReflectResult ParseExecutionModes( break; case SpvExecutionModeLocalSizeId: { - p_entry_point->local_size.flags = 1; + *p_entry_mode_flag = 1; CHECKED_READU32(p_parser, p_node->word_offset + 3, p_entry_point->local_size.x); CHECKED_READU32(p_parser, p_node->word_offset + 4, p_entry_point->local_size.y); CHECKED_READU32(p_parser, p_node->word_offset + 5, p_entry_point->local_size.z); @@ -3457,7 +3461,7 @@ static SpvReflectResult ParseExecutionModes( break; case SpvExecutionModeLocalSizeHint:{ - p_entry_point->local_size.flags = 2; + *p_entry_mode_flag = 2; CHECKED_READU32(p_parser, p_node->word_offset + 3, p_entry_point->local_size.x); CHECKED_READU32(p_parser, p_node->word_offset + 4, p_entry_point->local_size.y); CHECKED_READU32(p_parser, p_node->word_offset + 5, p_entry_point->local_size.z); @@ -3465,7 +3469,7 @@ static SpvReflectResult ParseExecutionModes( break; case SpvExecutionModeLocalSizeHintId: { - p_entry_point->local_size.flags = 3; + *p_entry_mode_flag = 3; CHECKED_READU32(p_parser, p_node->word_offset + 3, p_entry_point->local_size.x); CHECKED_READU32(p_parser, p_node->word_offset + 4, p_entry_point->local_size.y); CHECKED_READU32(p_parser, p_node->word_offset + 5, p_entry_point->local_size.z); @@ -3670,7 +3674,7 @@ static SpvReflectResult ParseSpecializationConstants(SpvReflectPrvParser* p_pars for (uint32_t j = 0; j < p_module->entry_point_count; ++j) { if (p_module->entry_points[j].spirv_execution_model == SpvExecutionModelKernel || p_module->entry_points[j].spirv_execution_model == SpvExecutionModelGLCompute) { - p_module->entry_points[j].local_size.flags = 4; + p_module->_internal->entry_point_mode_flags[j] = 4; p_module->entry_points[j].local_size.x = p_node->result_id; } } @@ -4457,6 +4461,21 @@ const SpvReflectEntryPoint* spvReflectGetEntryPoint( return NULL; } +int spvReflectGetEntryModeFlag( + const SpvReflectShaderModule* p_module, + const SpvReflectEntryPoint* p_entry +){ + if(IsNull(p_module) || IsNull(p_entry)){ + return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; + } + // signed + intptr_t index = p_entry - p_module->entry_points; + if(index < 0 || index >= p_module->entry_point_count){ + return SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND; + } + return p_module->_internal->entry_point_mode_flags[index]; +} + SpvReflectResult spvReflectEnumerateDescriptorBindings( const SpvReflectShaderModule* p_module, uint32_t* p_count, diff --git a/spirv_reflect.h b/spirv_reflect.h index 6e54ead4..b3bcabf5 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -80,6 +80,11 @@ typedef enum SpvReflectResult { SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_BLOCK_MEMBER_REFERENCE, SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ENTRY_POINT, SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_EXECUTION_MODE, + /* + Evaluation needs to validate spirv input to have no duplicate result ids. + Currently other parts of spirv-reflect does not take care of validating + the spirv, but this can go wrong with hand-written assembly + */ SPV_REFLECT_RESULT_ERROR_SPIRV_DUPLICATE_ID, SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_TYPE, SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION, @@ -269,10 +274,9 @@ typedef enum SpvReflectGenerator { } SpvReflectGenerator; enum { - // Vector16 capability allows larger vectors - SPV_REFLECT_MAX_VECTOR_DIMS = 16, SPV_REFLECT_MAX_ARRAY_DIMS = 32, SPV_REFLECT_MAX_DESCRIPTOR_SETS = 64, + SPV_REFLECT_MAX_VECTOR_DIMS = 16, // Vector16 capability allows larger vectors }; enum { @@ -342,20 +346,22 @@ typedef struct SpvReflectTypeDescription { uint32_t member_count; struct SpvReflectTypeDescription* members; - // for vector, array and matrix types - uint32_t component_type_id; + uint32_t component_type_id; // for vector, array and matrix types } SpvReflectTypeDescription; +/*! @struct SpvReflectScalarValueData +*/ typedef struct SpvReflectScalarValueData { + /* + Small types of size less than 32 bit are not implemented yet. + half float of 16 bit size not declared here yet. + */ union { - /* small types not implemented yet... */ - /* also remember float16 */ uint8_t uint8_value; int8_t sint8_value; uint16_t uint16_value; int16_t sint16_value; - /* types that are currently supported */ uint32_t uint32_bool_value; int32_t sint32_value; float float32_value; @@ -363,29 +369,51 @@ typedef struct SpvReflectScalarValueData { int64_t sint64_value; double float64_value; } value; - // for use with OpUndef + /* + for use with OpUndef. OpUndef gives undefined value. This tracks whether the ast have came through + a node with OpUndef or Op with parameters that gives undefined value. + Do note that: + x = Undef, 0 + x -x is always 0, but the undefined flag is set anyway. + Use as feature. + */ int undefined_value; } SpvReflectScalarValueData; +/*! @struct SpvReflectVectorValueData + +*/ typedef struct SpvReflectVectorValueData { SpvReflectScalarValueData value[SPV_REFLECT_MAX_VECTOR_DIMS]; } SpvReflectVectorValueData; -// only scalar, vector types can evaluate values for now... -// this struct is not meant to be created on user stack, -// instead in a internal dictionary and give user const ptr to read. +/*! @union SpvReflectValueNumericData + + Currently evaluation only supports scalar and vector types. + This struct is not meant to be created on user stack, + instead in a internal dictionary and give user const ptr to read. + User supplies const SpvReflectValueData** and recieve internal + const SpvReflectValueData* +*/ typedef union SpvReflectValueNumericData { SpvReflectScalarValueData scalar; SpvReflectVectorValueData vector; } SpvReflectValueNumericData; +/*! @union SpvReflectValueData + +*/ typedef union SpvReflectValueData { SpvReflectValueNumericData numeric; } SpvReflectValueData; +/*! @struct SpvReflectValue + +*/ typedef struct SpvReflectValue { - // never null in valid spirv - // means result type id + /* + This will never be null in valid spirv, which will have + corrctly parsed result type operand result. + */ SpvReflectTypeDescription* type; SpvReflectValueData data; }SpvReflectValue; @@ -529,13 +557,6 @@ typedef struct SpvReflectEntryPoint { uint32_t x; uint32_t y; uint32_t z; - int flags; // 0 if just fixed local size - // 1 bit set if is instruction id of spec constant - // 2 bit set if is hint (kernel mode not supported in vulkan, though) - // 4 bit is set if x is result_id decorated with WorkGroupSize - // this change may break abi - // if using specialization constants, - // xyz refers to evaluated result, not just constant_id } local_size; uint32_t invocations; // valid for geometry uint32_t output_vertices; // valid for geometry, tesselation @@ -606,8 +627,17 @@ typedef struct SpvReflectShaderModule { // stored as result id uint32_t builtin_WorkGroupSize; SpvReflectEvaluation* evaluator; + /* + Array of `entry_point_count` flags each extending SpvReflectEntryPoint + 0 if just fixed local size + 1 bit set if is instruction id of spec constant + 2 bit set if is hint (kernel mode not supported in vulkan, though) + 4 bit is set if x is result_id decorated with WorkGroupSize + if using specialization constants, + xyz refers to evaluated result, not just constant_id + */ + int* entry_point_mode_flags; } * _internal; - } SpvReflectShaderModule; #if defined(__cplusplus) @@ -689,6 +719,21 @@ const SpvReflectEntryPoint* spvReflectGetEntryPoint( const char* entry_point ); +/*! @fn spvReflectGetEntryModeFlag + + @param p_module Pointer to an instance of SpvReflectShaderModule. + @param p_entry entry point.pointer obtained from this p_module + @return Returns the flag if successful, or + SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND + if p_entry is not from p_module; + SPV_REFLECT_RESULT_ERROR_NULL_POINTER + if p_module or p_module is NULL +*/ +int spvReflectGetEntryModeFlag( + const SpvReflectShaderModule* p_module, + const SpvReflectEntryPoint* p_entry +); + /*! @fn spvReflectEnumerateDescriptorBindings @param p_module Pointer to an instance of SpvReflectShaderModule. @@ -1677,8 +1722,6 @@ SpvReflectResult spvReflectGetSpecializationInfo(const SpvReflectEvaluation* p_e namespace spv_reflect { // separate evaluation, so that module can be const. -class Evaluation; - /*! \class ShaderModule */ @@ -1696,7 +1739,6 @@ class ShaderModule { SpvReflectResult GetResult() const; const SpvReflectShaderModule& GetShaderModule() const; - Evaluation GetEvaluation() const; uint32_t GetCodeSize() const; const uint32_t* GetCode() const; @@ -1775,11 +1817,6 @@ class ShaderModule { SpvReflectResult ChangeInputVariableLocation(const SpvReflectInterfaceVariable* p_input_variable, uint32_t new_location); SpvReflectResult ChangeOutputVariableLocation(const SpvReflectInterfaceVariable* p_output_variable, uint32_t new_location); - SpvReflectEvaluation* GetEvaluationInterface() const - { - return spvReflectGetEvaluationInterface(&m_module); - } - private: // Make noncopyable ShaderModule(const ShaderModule&); @@ -1790,59 +1827,6 @@ class ShaderModule { SpvReflectShaderModule m_module = {}; }; -class Evaluation { -public: - Evaluation(SpvReflectEvaluation* eval) :p_eval(eval){} - SpvReflectResult SetSpecConstantValue(uint32_t specId, SpvReflectScalarType type, const SpvReflectScalarValueData* value) - { - if (p_eval) { - return spvReflectSetSpecConstantValue(p_eval, specId, type, value); - } - else { - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; - } - } - SpvReflectResult GetSpecConstantValue(uint32_t specId, const SpvReflectValue** value) - { - if (p_eval) { - return spvReflectGetSpecConstantValue(p_eval, specId, value); - } - else { - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; - } - } - SpvReflectResult EvaluateResult(uint32_t result_id, const SpvReflectValue** result) - { - if (p_eval) { - return spvReflectEvaluateResult(p_eval, result_id, result); - } - else { - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; - } - } - bool IsRelatedToSpecId(uint32_t result_id, uint32_t specId) - { - if (p_eval) { - return spvReflectIsRelatedToSpecId(p_eval, result_id, specId); - } - else { - return false; - } - } - SpvReflectResult GetSpecializationInfo(VkSpecializationInfo* info, VkSpecializationMapEntry* p_modifiable, uint32_t num_entries) - { - if (p_eval) { - return spvReflectGetSpecializationInfo(p_eval, info, p_modifiable, num_entries); - } - else{ - return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; - } - } -private: - SpvReflectEvaluation* p_eval; -}; - - // ================================================================================================= // ShaderModule // ================================================================================================= @@ -1934,12 +1918,6 @@ inline const SpvReflectShaderModule& ShaderModule::GetShaderModule() const { return m_module; } -inline Evaluation ShaderModule::GetEvaluation() const -{ - return Evaluation(spvReflectGetEvaluationInterface(&m_module)); -} - - /*! @fn GetCodeSize @return From cafdf08665ee6392e712c53a7e4afda4af687d33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sat, 20 May 2023 01:26:17 +0800 Subject: [PATCH 36/44] Fix conflict A merge error occurred in the last commit. Fixed in this one. --- common/output_stream.cpp | 8 ++++---- spirv_reflect.c | 6 +++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/common/output_stream.cpp b/common/output_stream.cpp index c45fb982..bc814113 100644 --- a/common/output_stream.cpp +++ b/common/output_stream.cpp @@ -1541,8 +1541,8 @@ void WriteReflection(const spv_reflect::ShaderModule& obj, const char* ttt = " "; const SpvReflectShaderModule& ref_module = obj.GetShaderModule(); - SpvReflectEvaluation* p_eval = spvReflectGetEvaluationInterface(&ref_module); - StreamWriteShaderModule(os, ref_module, p_eval, ""); + SpvReflectEvaluation* p_evaluator = spvReflectGetEvaluationInterface(&ref_module); + StreamWriteShaderModule(os, ref_module, p_evaluator, ""); uint32_t count = 0; std::vector variables; @@ -1634,7 +1634,7 @@ void WriteReflection(const spv_reflect::ShaderModule& obj, auto p_block = push_constant_bocks[i]; os << tt << i << ":" << "\n"; - StreamWritePushConstantsBlock(os, *p_block, obj.GetEvaluationInterface(), + StreamWritePushConstantsBlock(os, *p_block, p_evaluator, flatten_cbuffers, ttt); } } @@ -1664,7 +1664,7 @@ void WriteReflection(const spv_reflect::ShaderModule& obj, os << tt << "Binding" << " " << p_binding->set << "." << p_binding->binding << "" << "\n"; - StreamWriteDescriptorBinding(os, *p_binding, obj.GetEvaluationInterface(), + StreamWriteDescriptorBinding(os, *p_binding, p_evaluator, true, flatten_cbuffers, ttt); if (i < (count - 1)) { os << "\n\n"; diff --git a/spirv_reflect.c b/spirv_reflect.c index e2b7bcfd..358a6244 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -4147,7 +4147,11 @@ static SpvReflectResult CreateShaderModule( } // parser now works in internal field of p_module. - SpvReflectPrvParser parser = { 0 }; + // Initialize everything to zero + SpvReflectPrvParser parser; + memset(&parser, 0, sizeof(SpvReflectPrvParser)); + + // Create parser SpvReflectResult result = CreateParser(p_module->_internal->spirv_size, p_module->_internal->spirv_code, &parser); From a6adf7b2c29df8f2545504d93814ae02b6ed3eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sat, 20 May 2023 01:31:16 +0800 Subject: [PATCH 37/44] Fix broken tests Now localsize flag is not part of entry point struct. --- tests/test-spirv-reflect.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tests/test-spirv-reflect.cpp b/tests/test-spirv-reflect.cpp index 30d3301a..19836141 100644 --- a/tests/test-spirv-reflect.cpp +++ b/tests/test-spirv-reflect.cpp @@ -869,7 +869,7 @@ TEST(SpirvReflectTestCase, TestComputeLocalSize) { ASSERT_EQ(module_.entry_points[0].local_size.x, 1); ASSERT_EQ(module_.entry_points[0].local_size.y, 1); ASSERT_EQ(module_.entry_points[0].local_size.z, 1); - ASSERT_EQ(module_.entry_points[0].local_size.flags, 0); + ASSERT_EQ(spvReflectGetEntryModeFlag(&module_, &module_.entry_points[0]), 0); spvReflectDestroyShaderModule(&module_); } @@ -1239,7 +1239,7 @@ TEST(SpirvReflectSpecializationConstantTest, TestSpecParsing32) { EXPECT_EQ(module_.entry_point_count, 1); EXPECT_EQ(module_.entry_points[0].shader_stage, SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT); - EXPECT_EQ(module_.entry_points[0].local_size.flags, 4); + EXPECT_EQ(spvReflectGetEntryModeFlag(&module_, &module_.entry_points[0]), 4); ASSERT_EQ(module_.specialization_constant_count, 9); for (uint32_t i = 0; i < 9; ++i) { const SpvReflectSpecializationConstant* p_constant = &module_.specialization_constants[i]; @@ -1327,7 +1327,7 @@ TEST(SpirvReflectSpecializationConstantTest, TestSpecParsing64) EXPECT_EQ(module_.entry_point_count, 1); EXPECT_EQ(module_.entry_points[0].shader_stage, SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT); - EXPECT_EQ(module_.entry_points[0].local_size.flags, 4); + EXPECT_EQ(spvReflectGetEntryModeFlag(&module_, &module_.entry_points[0]), 4); ASSERT_EQ(module_.specialization_constant_count, 9); for (uint32_t i = 0; i < 9; ++i) { const SpvReflectSpecializationConstant* p_constant = &module_.specialization_constants[i]; @@ -1473,7 +1473,7 @@ TEST(SpirvReflectSpecializationConstantTest, TestEvaluate32) EXPECT_EQ(module_.entry_point_count, 1); EXPECT_EQ(module_.entry_points[0].shader_stage, SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT); - EXPECT_EQ(module_.entry_points[0].local_size.flags, 4); + EXPECT_EQ(spvReflectGetEntryModeFlag(&module_, &module_.entry_points[0]), 4); ASSERT_EQ(module_.specialization_constant_count, 9); SpvReflectEvaluation* p_eval = spvReflectGetEvaluationInterface(&module_); ASSERT_NE(p_eval, nullptr); @@ -1542,7 +1542,7 @@ TEST(SpirvReflectSpecializationConstantTest, TestEvaluate64) EXPECT_EQ(module_.entry_point_count, 1); EXPECT_EQ(module_.entry_points[0].shader_stage, SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT); - EXPECT_EQ(module_.entry_points[0].local_size.flags, 4); + EXPECT_EQ(spvReflectGetEntryModeFlag(&module_, &module_.entry_points[0]), 4); ASSERT_EQ(module_.specialization_constant_count, 9); SpvReflectEvaluation* p_eval = spvReflectGetEvaluationInterface(&module_); ASSERT_NE(p_eval, nullptr); @@ -1669,7 +1669,7 @@ TEST(SpirvReflectSpecializationConstantTest, TestInstancing) { EXPECT_EQ(module_.entry_point_count, 1); EXPECT_EQ(module_.entry_points[0].shader_stage, SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT); - EXPECT_EQ(module_.entry_points[0].local_size.flags, 4); + EXPECT_EQ(spvReflectGetEntryModeFlag(&module_, &module_.entry_points[0]), 4); ASSERT_EQ(module_.specialization_constant_count, 9); SpvReflectEvaluation* p_eval_orig = spvReflectGetEvaluationInterface(&module_); @@ -1732,7 +1732,8 @@ TEST(SpirvReflectSpecializationConstantTest, TestRelations) { EXPECT_EQ(module_.entry_point_count, 1); EXPECT_EQ(module_.entry_points[0].shader_stage, SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT); - EXPECT_EQ(module_.entry_points[0].local_size.flags, 4); + + EXPECT_EQ(spvReflectGetEntryModeFlag(&module_, &module_.entry_points[0]), 4); ASSERT_EQ(module_.specialization_constant_count, 9); SpvReflectEvaluation* p_eval = spvReflectGetEvaluationInterface(&module_); ASSERT_NE(p_eval, nullptr); @@ -1807,7 +1808,7 @@ TEST(SpirvReflectSpecializationConstantTest, TestMapEntry) { EXPECT_EQ(module_.entry_point_count, 1); EXPECT_EQ(module_.entry_points[0].shader_stage, SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT); - EXPECT_EQ(module_.entry_points[0].local_size.flags, 4); + EXPECT_EQ(spvReflectGetEntryModeFlag(&module_, &module_.entry_points[0]), 4); ASSERT_EQ(module_.specialization_constant_count, 9); SpvReflectEvaluation* p_eval = spvReflectGetEvaluationInterface(&module_); ASSERT_NE(p_eval, nullptr); From 64e256b3529b50576b7de622e4996b0c393be84c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Sat, 20 May 2023 02:12:10 +0800 Subject: [PATCH 38/44] remove wrong comment --- spirv_reflect.c | 1 - 1 file changed, 1 deletion(-) diff --git a/spirv_reflect.c b/spirv_reflect.c index 358a6244..8e36ccc4 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -4146,7 +4146,6 @@ static SpvReflectResult CreateShaderModule( memcpy(p_module->_internal->spirv_code, p_code, size); } - // parser now works in internal field of p_module. // Initialize everything to zero SpvReflectPrvParser parser; memset(&parser, 0, sizeof(SpvReflectPrvParser)); From 3ed6c760311316c475253d6c8e59f3dede3f005e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Wed, 12 Jul 2023 12:45:18 +0800 Subject: [PATCH 39/44] Fix memory leak Address [problem](https://github.com/shangjiaxuan/SPIRV-Reflect/commit/64e256b3529b50576b7de622e4996b0c393be84c#commitcomment-120952316) --- spirv_reflect.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spirv_reflect.c b/spirv_reflect.c index 8e36ccc4..133c64f0 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -4395,6 +4395,9 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module) } SafeFree(p_module->capabilities); SafeFree(p_module->entry_points); + if (p_module->_internal) { + SafeFree(p_module->_internal->entry_point_mode_flags); + } // Push constants for (size_t i = 0; i < p_module->push_constant_block_count; ++i) { From 0f941acc5251573cf5e5b89719b162a643ba8e1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Wed, 12 Jul 2023 14:26:35 +0800 Subject: [PATCH 40/44] Fix wrong text output. --- common/output_stream.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/output_stream.cpp b/common/output_stream.cpp index 54397612..43cf4ead 100644 --- a/common/output_stream.cpp +++ b/common/output_stream.cpp @@ -1500,10 +1500,10 @@ void StreamWriteEntryPoint(std::ostream& os, SpvReflectEvaluation* p_eval, const if (obj.shader_stage == SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT) { os << "\n"; if (entry_flag & 2) { - os << "local size : "; + os << "local size hint : "; } else { - os << "local size hint : "; + os << "local size : "; } if (entry_flag & 4) { const SpvReflectValue* val; From f722a55b822fd241b7340864242a9e5d405841bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Wed, 12 Jul 2023 15:05:54 +0800 Subject: [PATCH 41/44] Fix Linux CI build --- spirv_reflect.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spirv_reflect.c b/spirv_reflect.c index c69c8bb3..cef634c9 100644 --- a/spirv_reflect.c +++ b/spirv_reflect.c @@ -20,6 +20,8 @@ #include #include +#include // for offsetof as defined in c spec + #if defined(WIN32) #define _CRTDBG_MAP_ALLOC #include From 189f1dd4f3d282e6bfc120001ab01b3df37d2b50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Wed, 12 Jul 2023 15:29:17 +0800 Subject: [PATCH 42/44] Fix cpp binding formatting --- spirv_reflect.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spirv_reflect.h b/spirv_reflect.h index 9b5d1b88..b776bdb5 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -1788,9 +1788,8 @@ class ShaderModule { SpvReflectResult EnumeratePushConstants(uint32_t* p_count, SpvReflectBlockVariable** pp_blocks) const { return EnumeratePushConstantBlocks(p_count, pp_blocks); } - SpvReflectResult EnumerateSpecializationConstants(uint32_t* p_count, SpvReflectSpecializationConstant** pp_constants) const - { - return spvReflectEnumerateSpecializationConstants(&m_module, p_count, pp_constants); + SpvReflectResult EnumerateSpecializationConstants(uint32_t* p_count, SpvReflectSpecializationConstant** pp_constants) const { + return spvReflectEnumerateSpecializationConstants(&m_module, p_count, pp_constants); } const SpvReflectDescriptorBinding* GetDescriptorBinding(uint32_t binding_number, uint32_t set_number, SpvReflectResult* p_result = nullptr) const; From 973645bc264e8ea42b7bfe6a1a4771b69773b5c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Wed, 12 Jul 2023 15:31:44 +0800 Subject: [PATCH 43/44] remove blank line between function and comment --- spirv_reflect.h | 1 - 1 file changed, 1 deletion(-) diff --git a/spirv_reflect.h b/spirv_reflect.h index b776bdb5..d7b38c9b 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -1722,7 +1722,6 @@ typedef struct VkSpecializationMapEntry VkSpecializationMapEntry; Otherwise, the error code indicates the cause of the failure. */ - SpvReflectResult spvReflectGetSpecializationInfo(const SpvReflectEvaluation* p_eval, VkSpecializationInfo* info, VkSpecializationMapEntry* p_modifiable, uint32_t num_entries); #if defined(__cplusplus) From ae349aefaae4bea4cd207ecece416def4af1bb74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=9A=E5=98=89=E5=AE=A3?= <34389517+shangjiaxuan@users.noreply.github.com> Date: Thu, 13 Jul 2023 11:03:19 +0800 Subject: [PATCH 44/44] Clarify spvReflectGetSpecializationInfo documentation. --- spirv_reflect.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spirv_reflect.h b/spirv_reflect.h index d7b38c9b..414aa9c1 100644 --- a/spirv_reflect.h +++ b/spirv_reflect.h @@ -1713,7 +1713,10 @@ typedef struct VkSpecializationInfo VkSpecializationInfo; typedef struct VkSpecializationMapEntry VkSpecializationMapEntry; /* @fn spvReflectGetSpecializationInfo - @brief Call with nullptr to retrieve size of spec in entryCount, then allocate and call again. + @brief Helper function to fill VkSpecializationInfo with current SpvReflectEvaluation's state. + Specialization data is filled with SpvReflectEvaluation internal memory. + Call with nullptr to retrieve required count of VkSpecializationMapEntry in info->entryCount, + then allocate and call again. @param p_eval The evaluation interface @param info The info to be retrieved @param p_modifiable Pointer to modifiable entries allocated by user