diff --git a/CMakeLists.txt b/CMakeLists.txt index ecc0668b..f66d47ac 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,9 @@ if (SPIRV_REFLECT_BUILD_TESTS) CXX_STANDARD 11) target_compile_definitions(test-spirv-reflect PRIVATE $<$:_CRT_SECURE_NO_WARNINGS>) + 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 +118,9 @@ 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_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/README.md b/README.md index 98b83877..29204139 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,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 diff --git a/common/output_stream.cpp b/common/output_stream.cpp index 5de0d05b..43cf4ead 100644 --- a/common/output_stream.cpp +++ b/common/output_stream.cpp @@ -917,6 +917,7 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth, const std::string& parent_name, uint32_t member_count, const SpvReflectBlockVariable* p_members, + SpvReflectEvaluation* p_evaluator, std::vector* p_text_lines) { const char* t = indent; for (uint32_t member_index = 0; member_index < member_count; ++member_index) { @@ -966,7 +967,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, p_evaluator, p_target_text_line); tl.text_line_flags = TEXT_LINE_TYPE_LINES; p_text_lines->push_back(tl); @@ -996,6 +997,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 << "[]"; @@ -1033,7 +1041,14 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth, 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) { + 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 << "]"; } tl.name += ss_array.str(); } @@ -1050,6 +1065,7 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth, void ParseBlockVariableToTextLines(const char* indent, bool flatten_cbuffers, const SpvReflectBlockVariable& block_var, + SpvReflectEvaluation* p_evaluator, std::vector* p_text_lines) { // Begin block TextLine tl = {}; @@ -1066,7 +1082,7 @@ void ParseBlockVariableToTextLines(const char* indent, bool flatten_cbuffers, tl = {}; ParseBlockMembersToTextLines(indent, 2, flatten_cbuffers, "", block_var.member_count, block_var.members, - &tl.lines); + p_evaluator, &tl.lines); tl.text_line_flags = TEXT_LINE_TYPE_LINES; p_text_lines->push_back(tl); @@ -1286,6 +1302,7 @@ void StreamWriteTextLines(std::ostream& os, const char* indent, void StreamWritePushConstantsBlock(std::ostream& os, const SpvReflectBlockVariable& obj, + SpvReflectEvaluation* p_evaluator, bool flatten_cbuffers, const char* indent) { const char* t = indent; os << t << "spirv id : " << obj.spirv_id << "\n"; @@ -1298,7 +1315,8 @@ void StreamWritePushConstantsBlock(std::ostream& os, } std::vector text_lines; - ParseBlockVariableToTextLines(" ", flatten_cbuffers, obj, &text_lines); + ParseBlockVariableToTextLines(" ", flatten_cbuffers, obj, p_evaluator, + &text_lines); if (!text_lines.empty()) { os << "\n"; StreamWriteTextLines(os, t, flatten_cbuffers, text_lines); @@ -1308,6 +1326,7 @@ void StreamWritePushConstantsBlock(std::ostream& os, void StreamWriteDescriptorBinding(std::ostream& os, const SpvReflectDescriptorBinding& obj, + SpvReflectEvaluation* p_evaluator, bool write_set, bool flatten_cbuffers, const char* indent) { const char* t = indent; @@ -1359,7 +1378,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); + p_evaluator, &text_lines); if (!text_lines.empty()) { os << "\n"; StreamWriteTextLines(os, t, flatten_cbuffers, text_lines); @@ -1412,21 +1431,128 @@ void StreamWriteInterfaceVariable(std::ostream& os, } } -void StreamWriteEntryPoint(std::ostream& os, const SpvReflectEntryPoint& obj, - const char* indent) { +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, 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 hint : "; + } + else { + os << "local size : "; + } + 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) @@ -1438,7 +1564,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"; } @@ -1458,16 +1585,41 @@ 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_evaluator = spvReflectGetEvaluationInterface(&ref_module); + StreamWriteShaderModule(os, ref_module, p_evaluator, ""); uint32_t count = 0; std::vector variables; std::vector 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()); @@ -1527,7 +1679,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, p_evaluator, + flatten_cbuffers, ttt); } } @@ -1556,7 +1709,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, p_evaluator, + true, flatten_cbuffers, ttt); if (i < (count - 1)) { os << "\n\n"; } diff --git a/main.cpp b/main.cpp index be63920b..90a22b42 100644 --- a/main.cpp +++ b/main.cpp @@ -130,7 +130,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_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 f072f24e..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 @@ -134,6 +136,7 @@ typedef struct SpvReflectPrvDecorations { SpvReflectPrvNumberDecoration component; SpvReflectPrvNumberDecoration offset; SpvReflectPrvNumberDecoration uav_counter_buffer; + SpvReflectPrvNumberDecoration specialization_constant; SpvReflectPrvStringDecoration semantic; uint32_t array_stride; uint32_t matrix_stride; @@ -229,6 +232,79 @@ typedef struct SpvReflectPrvParser { } 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, + 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; + bool specialized; + + 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 { + const SpvReflectTypeDescription* src_type; + SpvReflectValueData* src_data; + } composite_extract; + struct CompositeInsert { + const 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, + 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 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 + SpvReflectShaderModule* member_type_finder; +} SpvReflectEvaluation; +// clang-format on + + static uint32_t Max(uint32_t a, uint32_t b) { return a > b ? a : b; } static uint32_t Min(uint32_t a, uint32_t b) { return a < b ? a : b; } @@ -535,7 +611,38 @@ static SpvReflectPrvNode* FindNode( return p_node; } -static SpvReflectTypeDescription* FindType(SpvReflectShaderModule* p_module, uint32_t type_id) +static SpvReflectPrvEvaluationNode* FindEvaluationNode( + const 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; + } + } + return p_node; +} + +static SpvReflectPrvEvaluationNode* FindSpecIdNode( + const 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; +} + +// const required for evaluation calls that need type info +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) { @@ -719,6 +826,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; @@ -925,12 +1033,7 @@ 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: @@ -1051,8 +1154,10 @@ 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))); - + 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]); @@ -1321,6 +1426,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; @@ -1421,7 +1529,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]); @@ -1453,6 +1562,7 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser) skip = true; } break; + case SpvDecorationSpecId: case SpvDecorationRelaxedPrecision: case SpvDecorationBlock: case SpvDecorationBufferBlock: @@ -1545,7 +1655,17 @@ 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; - 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; @@ -1611,6 +1731,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); @@ -1720,6 +1847,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)) { @@ -1737,6 +1867,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); @@ -1801,6 +1934,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; @@ -3311,7 +3447,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; } @@ -3429,8 +3567,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 @@ -3439,9 +3581,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; } } @@ -3454,6 +3598,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: { @@ -3484,13 +3632,37 @@ static SpvReflectResult ParseExecutionModes( break; case SpvExecutionModeLocalSize: { + *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); + } + break; + + case SpvExecutionModeLocalSizeId: { + *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); + } + break; + + case SpvExecutionModeLocalSizeHint:{ + *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); + } + break; + + case SpvExecutionModeLocalSizeHintId: { + *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); } break; - case SpvExecutionModeLocalSizeHint: case SpvExecutionModeInputPoints: case SpvExecutionModeInputLines: case SpvExecutionModeInputLinesAdjacency: @@ -3513,8 +3685,6 @@ static SpvReflectResult ParseExecutionModes( case SpvExecutionModeSubgroupSize: case SpvExecutionModeSubgroupsPerWorkgroup: case SpvExecutionModeSubgroupsPerWorkgroupId: - case SpvExecutionModeLocalSizeId: - case SpvExecutionModeLocalSizeHintId: case SpvExecutionModePostDepthCoverage: case SpvExecutionModeDenormPreserve: case SpvExecutionModeDenormFlushToZero: @@ -3580,6 +3750,282 @@ 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 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) + +#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 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; +} + +#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) \ + || ((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 +#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); +} + +#endif + +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; + 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++; + } + 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)); + if(IsNull(p_module->specialization_constants)){ + 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->_internal->entry_point_mode_flags[j] = 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]); + + // Specconstants with no id means constant + switch(p_node->op) { + 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; + SpvReflectScalarValueData default_value = { 0 }; + 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; + } 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_ID; + } + } + } + + 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++; + } +#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)); + 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_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; + } + + // 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_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].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_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_NODE_STATE_DONE; + } + else { + 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; + ++current_cinst; + current_offset += p_node->word_count; + } + } + + // 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 + EvaluateResult_1PASS(p_eval, p_ev_node, p_parser); + } + } + 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) && p_ev_node->evaluation_state == SPV_REFLECT_EVALUATION_NODE_STATE_UNINITIALIZED) { + literal_words += p_ev_node->num_literal_words; + id_operands += p_ev_node->num_id_operands; + } + } + if (id_operands) { + 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_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; + } + } + 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]; + 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_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; + } + } + 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]; + if(!IS_CONSTANT_LITERAL_OP(p_ev_node->op)){ + EvaluateResult_2PASS(p_eval, p_ev_node, p_parser); + } + } + } +#endif + return SPV_REFLECT_RESULT_SUCCESS; +} + +static void DestroyEvaluator(SpvReflectEvaluation* evaluator) +{ + SafeFree(evaluator->nodes); + + SafeFree(evaluator->id_operands); + SafeFree(evaluator->literal_words); +} + + static SpvReflectResult ParsePushConstantBlocks( SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) @@ -3815,7 +4261,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]); @@ -3892,6 +4340,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 @@ -3958,7 +4407,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); } @@ -4032,6 +4481,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) { @@ -4162,6 +4616,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) { @@ -4183,6 +4640,16 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module) if ((p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_NO_COPY) == 0) { SafeFree(p_module->_internal->spirv_code); } + + 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 SafeFree(p_module->_internal); } @@ -4221,6 +4688,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, @@ -4462,6 +4944,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, @@ -5333,3 +5845,2093 @@ const char* spvReflectBlockVariableTypeName( } return p_var->type_description->type_name; } + +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; + } + } + 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; + } + } + else { + return SPV_REFLECT_RESULT_ERROR_SPIRV_UNRESOLVED_EVALUATION; + } +} + +#if SPIRV_REFLECT_ENABLE_CONSTANT_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(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; \ + } \ + } \ +} + +#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)) { \ + 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; \ + } \ + } \ +} + +#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) +#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_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 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) \ + CHECK_IF_VECTOR_SIZE_MATCH_1OP((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) \ +{ \ + 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) \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(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; \ + } \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP((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, _32bit_type, _64bit_type, _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) \ + 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: \ + { \ + _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; \ + } \ + break; \ + case 64: \ + { \ + _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; \ + } \ + 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) \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(simple_op_node, simple_op_node->id_operands[0], simple_op_node->id_operands[1], res, CLEANUP) \ + } \ + break; \ + } \ +} + +#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) { \ + 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) \ + \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(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) \ + \ + CHECK_IF_VECTOR_SIZE_MATCH_2OP(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 EvaluateResult_Impl(SpvReflectEvaluation* p_eval, SpvReflectPrvEvaluationNode* p_node, SpvReflectEvaluationMode evaluation_mode, SpvReflectPrvParser* p_parser) +{ + 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_SPIRV_EVAL_TREE_INIT_FAILED; + case SPV_REFLECT_EVALUATION_NODE_STATE_INIT_FAILED: + 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; + 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_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: + 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_SPIRV_UNRESOLVED_EVALUATION; + 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; + } + + 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: + { + 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: + { + 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 + 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: + { + 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; + } + } + 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->specOp) { + default: + res = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION; + 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; + } + CHECK_IF_VECTOR_SIZE_MATCH_1OP(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; + } + CHECK_IF_VECTOR_SIZE_MATCH_1OP(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 + CHECK_IF_VECTOR_SIZE_MATCH_1OP(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_LOGICAL_SHIFT_OPERATION(evaluation_mode, p_parser, p_eval, p_node, >> , res, CLEANUP) + break; + case SpvOpShiftRightArithmetic: + // fill with sign of original number. + 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_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) + 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; + 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; + } + } + 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 = 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) + 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; + 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); + 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; + } + } + 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 = 0; + } + 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; + 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); + 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) + + CHECK_IF_VECTOR_SIZE_MATCH_1OP(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; + } + 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; + } + } + 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: + 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; +} + + +SpvReflectEvaluation* spvReflectGetEvaluationInterface(const SpvReflectShaderModule* p_module) +{ + 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; + } + 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; +} + +SpvReflectResult spvReflectSetSpecConstantValue(SpvReflectEvaluation* p_eval, uint32_t specId, SpvReflectScalarType type, const SpvReflectScalarValueData* value) +{ + 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->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) { + 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; +} + +SpvReflectResult spvReflectGetSpecConstantValue(SpvReflectEvaluation* p_eval, uint32_t specId, const SpvReflectValue** value) +{ + 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; +} + +int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id, uint32_t specId) +{ + 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); +} + +#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) +{ + 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) { + 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; + } + ++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; +} + +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); + 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]; + } + // 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; + } + } + } + + p_copied->member_type_finder = p_eval->member_type_finder; + + 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) +{ + (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_EVAL_TREE_INIT_FAILED; +} + +int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id, uint32_t specId) +{ + (void)p_eval; + (void)result_id; + (void)specId; + 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; +} + +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 aea5e8b2..414aa9c1 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__) @@ -79,6 +80,15 @@ 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, + SPV_REFLECT_RESULT_ERROR_SPIRV_EVAL_TREE_INIT_FAILED } SpvReflectResult; /*! @enum SpvReflectModuleFlagBits @@ -92,10 +102,15 @@ 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 - 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, - 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_CONSTANT = 0x00000002 } SpvReflectModuleFlagBits; typedef uint32_t SpvReflectModuleFlags; @@ -274,6 +289,7 @@ typedef enum SpvReflectGenerator { enum { 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,8 +358,91 @@ typedef struct SpvReflectTypeDescription { uint32_t member_count; struct SpvReflectTypeDescription* members; + + 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 { + uint8_t uint8_value; + int8_t sint8_value; + uint16_t uint16_value; + int16_t sint16_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. 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; + +/*! @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 { + /* + This will never be null in valid spirv, which will have + corrctly parsed result type operand result. + */ + SpvReflectTypeDescription* type; + SpvReflectValueData data; +}SpvReflectValue; + +/*! @struct SpvReflectSpecializationConstant + +*/ +typedef struct SpvReflectSpecializationConstant { + uint32_t spirv_id; + uint32_t constant_id; + + SpvReflectTypeDescription* type; + const char* name; + + SpvReflectScalarValueData default_value; +} SpvReflectSpecializationConstant; /*! @struct SpvReflectInterfaceVariable @@ -486,6 +585,16 @@ typedef struct SpvReflectCapability { uint32_t word_offset; } SpvReflectCapability; +/*! @struct SpvReflectEvaluation + @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; + /*! @struct SpvReflectShaderModule */ @@ -516,6 +625,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; @@ -524,8 +636,23 @@ typedef struct SpvReflectShaderModule { size_t type_description_count; SpvReflectTypeDescription* type_descriptions; - } * _internal; + // 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; + /* + 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) @@ -607,6 +734,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. @@ -787,6 +929,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. @@ -1454,6 +1621,112 @@ const char* spvReflectBlockVariableTypeName( const SpvReflectBlockVariable* p_var ); + +/*! @fn spvReflectGetEvaluationInterface + @brief Retrieves the handle for evaluation + @param p_module Pointer to an instance of SpvReflectShaderModule. + @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, + 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); + +/*! @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 (may be a silent error) +*/ +int spvReflectIsRelatedToSpecId(SpvReflectEvaluation* p_eval, uint32_t result_id, uint32_t specId); + +/* + types used, but defined in vulkan.h +*/ +typedef struct VkSpecializationInfo VkSpecializationInfo; +typedef struct VkSpecializationMapEntry VkSpecializationMapEntry; + +/* @fn spvReflectGetSpecializationInfo + @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 + @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) }; #endif @@ -1465,6 +1738,7 @@ const char* spvReflectBlockVariableTypeName( namespace spv_reflect { +// separate evaluation, so that module can be const. /*! \class ShaderModule */ @@ -1516,6 +1790,9 @@ 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; @@ -1566,7 +1843,6 @@ class ShaderModule { SpvReflectShaderModule m_module = {}; }; - // ================================================================================================= // ShaderModule // ================================================================================================= @@ -1658,7 +1934,6 @@ inline const SpvReflectShaderModule& ShaderModule::GetShaderModule() const { return m_module; } - /*! @fn GetCodeSize @return diff --git a/tests/spec_constant/rebuild.sh b/tests/spec_constant/rebuild.sh new file mode 100644 index 00000000..a21519f2 --- /dev/null +++ b/tests/spec_constant/rebuild.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# 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 +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 00000000..7a8f6023 Binary files /dev/null and b/tests/spec_constant/test_32bit.spv differ diff --git a/tests/spec_constant/test_32bit.spv.dis b/tests/spec_constant/test_32bit.spv.dis new file mode 100644 index 00000000..a20ac030 --- /dev/null +++ b/tests/spec_constant/test_32bit.spv.dis @@ -0,0 +1,673 @@ +; SPIR-V +; Version: 1.5 +; Generator: Google Shaderc over Glslang; 10 +; Bound: 267 +; 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 %SNEG_TWO "SNEG_TWO" + 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_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 %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 %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_39 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_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_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 %_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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 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 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 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 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 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 30 + OpDecorate %262 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 + %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 + %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 +%_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_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 + %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 + %SMOD = OpSpecConstantOp %int SMod %STWO %SNEG_THREE + %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 + %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 + %83 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %LSHL = OpSpecConstantOp %uint ShiftLeftLogical %IADD %83 + %uint_11 = OpConstant %uint 11 + %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 + %92 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %RSHL = OpSpecConstantOp %uint ShiftRightLogical %IADD %92 + %uint_2 = OpConstant %uint 2 + %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 + %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 + %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 %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 + %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 + %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 + %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 + %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 + %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 %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 %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 %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 %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 + %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 + %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 + %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 + %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 + %217 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %OR = OpSpecConstantOp %uint BitwiseOr %IADD %217 + %uint_6 = OpConstant %uint 6 + %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 + %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 + %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 + %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 + %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 + %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 + %262 = OpSpecConstant %uint 4 + %v3uint = OpTypeVector %uint 3 +%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 + %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 + %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 new file mode 100644 index 00000000..0186613d --- /dev/null +++ b/tests/spec_constant/test_32bit.spv.dis.patch @@ -0,0 +1,14 @@ +10c10,11 +< OpExecutionMode %main LocalSize 1 1 1 +--- +> ; should ignore this if working with WorkGroupSize builtin +> OpExecutionMode %main LocalSize 2 3 4 +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 +> %262 = OpSpecConstant %uint 4 diff --git a/tests/spec_constant/test_64bit.spv b/tests/spec_constant/test_64bit.spv new file mode 100644 index 00000000..e739b65f Binary files /dev/null and b/tests/spec_constant/test_64bit.spv differ diff --git a/tests/spec_constant/test_64bit.spv.dis b/tests/spec_constant/test_64bit.spv.dis new file mode 100644 index 00000000..3791171a --- /dev/null +++ b/tests/spec_constant/test_64bit.spv.dis @@ -0,0 +1,676 @@ +; SPIR-V +; Version: 1.5 +; Generator: Google Shaderc over Glslang; 10 +; Bound: 267 +; Schema: 0 + OpCapability Shader + OpCapability Int64 + %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 %SNEG_TWO "SNEG_TWO" + 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_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 %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 %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_39 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_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_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 %_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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 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 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 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 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 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 30 + OpDecorate %262 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 64 1 + %SONE = OpSpecConstant %int 1 + %STWO = OpSpecConstant %int 2 + %10 = OpSpecConstantOp %int IAdd %SONE %STWO + %uint_orig = OpTypeInt 32 0 + %uint = OpTypeInt 64 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 + %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 + %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 +%_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_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 +%uint_orig_1 = OpConstant %uint_orig 1 +%_ptr_StorageBuffer_SSBO_SDiv = OpTypePointer StorageBuffer %SSBO_SDiv + %SDiv = OpVariable %_ptr_StorageBuffer_SSBO_SDiv StorageBuffer + %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 + %SMOD = OpSpecConstantOp %int SMod %STWO %SNEG_THREE + %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 + %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 + %83 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %LSHL = OpSpecConstantOp %uint ShiftLeftLogical %IADD %83 + %uint_11 = OpConstant %uint 11 + %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 + %92 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %RSHL = OpSpecConstantOp %uint ShiftRightLogical %IADD %92 + %uint_2 = OpConstant %uint 2 + %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 + %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 + %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 %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 + %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 + %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 + %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 + %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 + %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 %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 %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 %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 %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 + %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 + %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 + %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 + %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 + %217 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %OR = OpSpecConstantOp %uint BitwiseOr %IADD %217 + %uint_6 = OpConstant %uint 6 + %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 + %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_18446744073709551614 = OpConstant %uint 18446744073709551614 + %235 = OpSpecConstantOp %uint ISub %NOT %uint_18446744073709551614 +%_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 + %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 + %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 + %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 + %262 = OpSpecConstant %uint_orig 4 +%v3uint_orig = OpTypeVector %uint_orig 3 +%gl_WorkGroupSize = OpSpecConstantComposite %v3uint_orig %262 %uint_orig_1 %uint_orig_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 + %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 + %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_64bit.spv.dis.patch b/tests/spec_constant/test_64bit.spv.dis.patch new file mode 100644 index 00000000..61f6f4f5 --- /dev/null +++ b/tests/spec_constant/test_64bit.spv.dis.patch @@ -0,0 +1,37 @@ +6a7 +> OpCapability Int64 +10c11,12 +< OpExecutionMode %main LocalSize 1 1 1 +--- +> ; should ignore this if working with WorkGroupSize builtin +> OpExecutionMode %main LocalSize 2 3 4 +377c379 +< %int = OpTypeInt 32 1 +--- +> %int = OpTypeInt 64 1 +381c383,384 +< %uint = OpTypeInt 32 0 +--- +> %uint_orig = OpTypeInt 32 0 +> %uint = OpTypeInt 64 0 +422a426 +> %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 %262 %uint_1 %uint_1 +--- +> ; default value should be respected, even if no compiler write things other than 1 +> %262 = OpSpecConstant %uint_orig 4 +> %v3uint_orig = OpTypeVector %uint_orig 3 +> %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 new file mode 100644 index 00000000..ad737005 --- /dev/null +++ b/tests/spec_constant/test_convert.glsl @@ -0,0 +1,34 @@ +#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 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); + +const int S_SONE = int(SONE); +const int S_UONE = int(UONE); + +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 + +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] = 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 new file mode 100644 index 00000000..fd6b7feb Binary files /dev/null and b/tests/spec_constant/test_convert.spv differ diff --git a/tests/spec_constant/test_convert.spv.dis b/tests/spec_constant/test_convert.spv.dis new file mode 100644 index 00000000..e1372feb --- /dev/null +++ b/tests/spec_constant/test_convert.spv.dis @@ -0,0 +1,126 @@ +; SPIR-V +; Version: 1.5 +; Generator: Google Shaderc over Glslang; 10 +; Bound: 50 +; 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 %F_ONE "F_ONE" + 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 %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 "D_ONE2" + 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 %F_ONE 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 %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 + 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 + %F_ONE = OpSpecConstant %float 1 +%_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 + %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 + %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 %F_ONE + %main = OpFunction %void None %3 + %5 = OpLabel + %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 new file mode 100644 index 00000000..6d47e7c5 --- /dev/null +++ b/tests/spec_constant/test_convert.spv.dis.patch @@ -0,0 +1,24 @@ +37c37 +< OpName %F_ONE2 "F_ONE2" +--- +> OpName %9999 "F_ONE2" +43c43 +< OpName %D_ONE2 "D_ONE2" +--- +> OpName %10000 "D_ONE2" +104c104 +< %F_ONE2 = OpSpecConstantOp %float FConvert %D_ONE +--- +> %9999 = OpSpecConstantOp %float FConvert %D_ONE +114c114 +< %D_ONE2 = OpSpecConstantOp %double FConvert %F_ONE +--- +> %10000 = OpSpecConstantOp %double FConvert %F_ONE +122c122 +< OpStore %38 %F_ONE2 +--- +> OpStore %38 %9999 +124c124 +< OpStore %45 %F_ONE2 +--- +> OpStore %45 %9999 diff --git a/tests/spec_constant/test_localsizeid.spv b/tests/spec_constant/test_localsizeid.spv new file mode 100644 index 00000000..808b0269 Binary files /dev/null and b/tests/spec_constant/test_localsizeid.spv differ diff --git a/tests/spec_constant/test_localsizeid.spv.dis b/tests/spec_constant/test_localsizeid.spv.dis new file mode 100644 index 00000000..215b18fe --- /dev/null +++ b/tests/spec_constant/test_localsizeid.spv.dis @@ -0,0 +1,669 @@ +; SPIR-V +; Version: 1.5 +; Generator: Google Shaderc over Glslang; 10 +; Bound: 267 +; 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 + OpExecutionModeId %main LocalSizeId %262 %uint_1 %uint_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 %SNEG_TWO "SNEG_TWO" + 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_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 %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 %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_39 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_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_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 %_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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 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 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 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 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 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 30 + OpDecorate %262 SpecId 8 + 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 + %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 + %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 +%_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_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 + %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 + %SMOD = OpSpecConstantOp %int SMod %STWO %SNEG_THREE + %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 + %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 + %83 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %LSHL = OpSpecConstantOp %uint ShiftLeftLogical %IADD %83 + %uint_11 = OpConstant %uint 11 + %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 + %92 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %RSHL = OpSpecConstantOp %uint ShiftRightLogical %IADD %92 + %uint_2 = OpConstant %uint 2 + %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 + %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 + %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 %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 + %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 + %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 + %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 + %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 + %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 %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 %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 %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 %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 + %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 + %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 + %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 + %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 + %217 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %OR = OpSpecConstantOp %uint BitwiseOr %IADD %217 + %uint_6 = OpConstant %uint 6 + %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 + %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 + %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 + %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 + %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 + %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 + %262 = OpSpecConstant %uint 4 + %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 + %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 + %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_localsizeid.spv.dis.patch b/tests/spec_constant/test_localsizeid.spv.dis.patch new file mode 100644 index 00000000..fbdc30fe --- /dev/null +++ b/tests/spec_constant/test_localsizeid.spv.dis.patch @@ -0,0 +1,17 @@ +10c10 +< OpExecutionMode %main LocalSize 1 1 1 +--- +> OpExecutionModeId %main LocalSizeId %262 %uint_1 %uint_1 +371d370 +< OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize +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 %262 %uint_1 %uint_1 +--- +> ; default value should be respected, even if no compiler write things other than 1 +> %262 = 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..c24698fa --- /dev/null +++ b/tests/spec_constant/test_orig.glsl @@ -0,0 +1,122 @@ +#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 - SNEG_TWO; // 4 +const uint IMUL = UTWO * UTWO; // 4 +const uint UDIV = UTWO / UTWO; // 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 - 3); // 12 +const uint RSHL = IADD >> (ISUB - 3); // 3 +const int RSHA = (-int(IADD)) >> (1-SDIV); // -3 + +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 +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 - 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 - 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 - 3); +DUMMY_SSBO(IMul, 2, IMUL - 3); +DUMMY_SSBO(UDiv, 3, UDIV); +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); +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, 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() +{ + 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..97255a44 --- /dev/null +++ b/tests/spec_constant/test_orig.spv.dis @@ -0,0 +1,671 @@ +; SPIR-V +; Version: 1.5 +; Generator: Google Shaderc over Glslang; 10 +; Bound: 267 +; 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 %SNEG_TWO "SNEG_TWO" + 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_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 %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 %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_39 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_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_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 %_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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 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 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 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 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 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 30 + OpDecorate %262 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 + %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 + %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 +%_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_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 + %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 + %SMOD = OpSpecConstantOp %int SMod %STWO %SNEG_THREE + %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 + %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 + %83 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %LSHL = OpSpecConstantOp %uint ShiftLeftLogical %IADD %83 + %uint_11 = OpConstant %uint 11 + %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 + %92 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %RSHL = OpSpecConstantOp %uint ShiftRightLogical %IADD %92 + %uint_2 = OpConstant %uint 2 + %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 + %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 + %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 %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 + %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 + %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 + %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 + %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 + %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 %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 %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 %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 %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 + %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 + %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 + %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 + %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 + %217 = OpSpecConstantOp %uint ISub %ISUB %uint_3 + %OR = OpSpecConstantOp %uint BitwiseOr %IADD %217 + %uint_6 = OpConstant %uint 6 + %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 + %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 + %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 + %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 + %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 + %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 + %262 = OpSpecConstant %uint 1 + %v3uint = OpTypeVector %uint 3 +%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 + %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 + %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 651dacaa..1a70a32d 100644 --- a/tests/test-spirv-reflect.cpp +++ b/tests/test-spirv-reflect.cpp @@ -874,6 +874,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(spvReflectGetEntryModeFlag(&module_, &module_.entry_points[0]), 0); spvReflectDestroyShaderModule(&module_); } @@ -1225,3 +1226,626 @@ TEST_F(SpirvReflectMultiEntryPointTest, ChangeDescriptorSetNumber) { ASSERT_EQ(set0->bindings[0], set1->bindings[1]); ASSERT_EQ(set0->bindings[0]->set, 1); } + +TEST(SpirvReflectSpecializationConstantTest, TestSpecParsing32) { + 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 = + 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(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]; + 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(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]; + 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); + 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); + // 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_); +} + +#if SPIRV_REFLECT_ENABLE_CONSTANT_EVALUATION +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(spvReflectGetEntryModeFlag(&module_, &module_.entry_points[0]), 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(spvReflectGetEntryModeFlag(&module_, &module_.entry_points[0]), 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); + } +} + +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(spvReflectGetEntryModeFlag(&module_, &module_.entry_points[0]), 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(spvReflectGetEntryModeFlag(&module_, &module_.entry_points[0]), 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(spvReflectGetEntryModeFlag(&module_, &module_.entry_points[0]), 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