diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index 7a6751c1f..417f9c8cf 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2019.5-dev", "SPIRV-Tools v2019.5-dev v2019.4-120-g2276e597" +"v2019.5-dev", "SPIRV-Tools v2019.5-dev v2019.4-133-ge8c3f9b0" diff --git a/3rdparty/spirv-tools/source/CMakeLists.txt b/3rdparty/spirv-tools/source/CMakeLists.txt index a083995c4..f3b5942bc 100644 --- a/3rdparty/spirv-tools/source/CMakeLists.txt +++ b/3rdparty/spirv-tools/source/CMakeLists.txt @@ -340,7 +340,7 @@ spvtools_default_compile_options(${SPIRV_TOOLS}) target_include_directories(${SPIRV_TOOLS} PUBLIC $ - $ + $ PRIVATE ${spirv-tools_BINARY_DIR} PRIVATE ${SPIRV_HEADER_INCLUDE_DIR} ) @@ -353,7 +353,7 @@ spvtools_default_compile_options(${SPIRV_TOOLS}-shared) target_include_directories(${SPIRV_TOOLS}-shared PUBLIC $ - $ + $ PRIVATE ${spirv-tools_BINARY_DIR} PRIVATE ${SPIRV_HEADER_INCLUDE_DIR} ) @@ -379,7 +379,17 @@ if(ENABLE_SPIRV_TOOLS_INSTALL) RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - install(EXPORT ${SPIRV_TOOLS}Targets DESTINATION lib/cmake) + export(EXPORT ${SPIRV_TOOLS}Targets FILE ${SPIRV_TOOLS}Target.cmake) + + spvtools_config_package_dir(${SPIRV_TOOLS} PACKAGE_DIR) + install(EXPORT ${SPIRV_TOOLS}Targets FILE ${SPIRV_TOOLS}Target.cmake DESTINATION ${PACKAGE_DIR}) + + # Special config file for root library compared to other libs. + file(WRITE ${CMAKE_BINARY_DIR}/${SPIRV_TOOLS}Config.cmake + "include(\${CMAKE_CURRENT_LIST_DIR}/${SPIRV_TOOLS}Target.cmake)\n" + "set(${SPIRV_TOOLS}_LIBRARIES ${SPIRV_TOOLS})\n" + "get_target_property(${SPIRV_TOOLS}_INCLUDE_DIRS ${SPIRV_TOOLS} INTERFACE_INCLUDE_DIRECTORIES)\n") + install(FILES ${CMAKE_BINARY_DIR}/${SPIRV_TOOLS}Config.cmake DESTINATION ${PACKAGE_DIR}) endif(ENABLE_SPIRV_TOOLS_INSTALL) if(MSVC) diff --git a/3rdparty/spirv-tools/source/binary.cpp b/3rdparty/spirv-tools/source/binary.cpp index 636dac8c8..1d3128373 100644 --- a/3rdparty/spirv-tools/source/binary.cpp +++ b/3rdparty/spirv-tools/source/binary.cpp @@ -781,9 +781,10 @@ spv_result_t spvBinaryParse(const spv_const_context context, void* user_data, // TODO(dneto): This probably belongs in text.cpp since that's the only place // that a spv_binary_t value is created. void spvBinaryDestroy(spv_binary binary) { - if (!binary) return; - delete[] binary->code; - delete binary; + if (binary) { + if (binary->code) delete[] binary->code; + delete binary; + } } size_t spv_strnlen_s(const char* str, size_t strsz) { diff --git a/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt b/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt index 11c9219e1..587a05a83 100644 --- a/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt +++ b/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt @@ -153,8 +153,6 @@ if(SPIRV_BUILD_FUZZER) target_include_directories(SPIRV-Tools-fuzz PUBLIC $ - $ - PUBLIC $ $ PRIVATE ${spirv-tools_BINARY_DIR} @@ -174,7 +172,14 @@ if(SPIRV_BUILD_FUZZER) RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - install(EXPORT SPIRV-Tools-fuzzTargets DESTINATION lib/cmake) + export(EXPORT SPIRV-Tools-fuzzTargets FILE SPIRV-Tools-fuzzTarget.cmake) + + spvtools_config_package_dir(SPIRV-Tools-fuzz PACKAGE_DIR) + install(EXPORT SPIRV-Tools-fuzzTargets FILE SPIRV-Tools-fuzzTarget.cmake + DESTINATION ${PACKAGE_DIR}) + + spvtools_generate_config_file(SPIRV-Tools-fuzz) + install(FILES ${CMAKE_BINARY_DIR}/SPIRV-Tools-fuzzConfig.cmake DESTINATION ${PACKAGE_DIR}) endif(ENABLE_SPIRV_TOOLS_INSTALL) endif(SPIRV_BUILD_FUZZER) diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp index cb26d79ae..1da53f426 100644 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.cpp @@ -14,6 +14,8 @@ #include "source/fuzz/fuzzer_pass.h" +#include "source/fuzz/instruction_descriptor.h" + namespace spvtools { namespace fuzz { @@ -69,9 +71,10 @@ std::vector FuzzerPass::FindAvailableInstructions( } void FuzzerPass::MaybeAddTransformationBeforeEachInstruction( - std::function + std::function< + void(const opt::Function& function, opt::BasicBlock* block, + opt::BasicBlock::iterator inst_it, + const protobufs::InstructionDescriptor& instruction_descriptor)> maybe_apply_transformation) { // Consider every block in every function. for (auto& function : *GetIRContext()->module()) { @@ -80,46 +83,45 @@ void FuzzerPass::MaybeAddTransformationBeforeEachInstruction( // whether to apply a transformation before it. // In order for transformations to insert new instructions, they need to - // be able to identify the instruction to insert before. We enable this - // by tracking a base instruction, which must generate a result id, and - // an offset (to allow us to identify instructions that do not generate - // result ids). + // be able to identify the instruction to insert before. We describe an + // instruction via its opcode, 'opc', a base instruction 'base' that has a + // result id, and the number of instructions with opcode 'opc' that we + // should skip when searching from 'base' for the desired instruction. + // (An instruction that has a result id is represented by its own opcode, + // itself as 'base', and a skip-count of 0.) + std::vector> + base_opcode_skip_triples; // The initial base instruction is the block label. uint32_t base = block.id(); - uint32_t offset = 0; - // Consider every instruction in the block. + + // Counts the number of times we have seen each opcode since we reset the + // base instruction. + std::map skip_count; + + // Consider every instruction in the block. The label is excluded: it is + // only necessary to consider it as a base in case the first instruction + // in the block does not have a result id. for (auto inst_it = block.begin(); inst_it != block.end(); ++inst_it) { if (inst_it->HasResultId()) { // In the case that the instruction has a result id, we use the - // instruction as its own base, with zero offset. + // instruction as its own base, and clear the skip counts we have + // collected. base = inst_it->result_id(); - offset = 0; - } else { - // The instruction does not have a result id, so we need to identify - // it via the latest instruction that did have a result id (base), and - // an incremented offset. - offset++; + skip_count.clear(); } + const SpvOp opcode = inst_it->opcode(); // Invoke the provided function, which might apply a transformation. - // Its return value informs us of how many instructions it inserted. - // (This will be 0 if no transformation was applied.) - uint32_t num_instructions_inserted = - maybe_apply_transformation(function, &block, inst_it, base, offset); + maybe_apply_transformation( + function, &block, inst_it, + MakeInstructionDescriptor( + base, opcode, + skip_count.count(opcode) ? skip_count.at(opcode) : 0)); if (!inst_it->HasResultId()) { - // We are tracking the current id-less instruction via an offset, - // |offset|, from a previous instruction, |base|, that has an id. We - // increment |offset| to reflect any newly-inserted instructions. - // - // An alternative would be to reset |base| to be an id generated by - // a newly-inserted instruction, but that would be more complex, and - // sticking to a |base| that already existed before this - // transformation was applied makes the applicability of future - // transformations less tightly coupled with the presence of the just- - // applied transformation. - offset += num_instructions_inserted; + skip_count[opcode] = + skip_count.count(opcode) ? skip_count.at(opcode) + 1 : 1; } } } diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.h index d56cc534e..cf56e2407 100644 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.h +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass.h @@ -67,27 +67,26 @@ class FuzzerPass { instruction_is_relevant); // A helper method that iterates through each instruction in each block, at - // all times tracking a base instruction and offset that allows that latest + // all times tracking an instruction descriptor that allows the latest // instruction to be located even if it has no result id. // - // The code to manipulate the base and offset is a bit fiddly, and the point - // of this method is to avoiding having to duplicate it in multiple + // The code to manipulate the instruction descriptor is a bit fiddly, and the + // point of this method is to avoiding having to duplicate it in multiple // transformation passes. // // The function |maybe_apply_transformation| is invoked for each instruction // |inst_it| in block |block| of function |function| that is encountered. The - // |base| and |offset| parameters to the function object allow |inst_it| to be - // identified. + // |instruction_descriptor| parameter to the function object allows |inst_it| + // to be identified. // // The job of |maybe_apply_transformation| is to randomly decide whether to // try to apply some transformation, and then - if selected - to attempt to - // apply it. The function returns the number of instructions that were - // inserted before |inst_it|, so that |offset| can be updated. - // + // apply it. void MaybeAddTransformationBeforeEachInstruction( - std::function + std::function< + void(const opt::Function& function, opt::BasicBlock* block, + opt::BasicBlock::iterator inst_it, + const protobufs::InstructionDescriptor& instruction_descriptor)> maybe_apply_transformation); private: diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp index e0d21840b..f8ad41b1e 100644 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp @@ -43,21 +43,22 @@ void FuzzerPassConstructComposites::Apply() { } MaybeAddTransformationBeforeEachInstruction( - [this, &composite_type_ids](const opt::Function& function, - opt::BasicBlock* block, - opt::BasicBlock::iterator inst_it, - uint32_t base, uint32_t offset) -> uint32_t { + [this, &composite_type_ids]( + const opt::Function& function, opt::BasicBlock* block, + opt::BasicBlock::iterator inst_it, + const protobufs::InstructionDescriptor& instruction_descriptor) + -> void { // Check whether it is legitimate to insert a composite construction // before the instruction. if (!fuzzerutil::CanInsertOpcodeBeforeInstruction( SpvOpCompositeConstruct, inst_it)) { - return 0; + return; } // Randomly decide whether to try inserting an object copy here. if (!GetFuzzerContext()->ChoosePercentage( GetFuzzerContext()->GetChanceOfConstructingComposite())) { - return 0; + return; } // For each instruction that is available at this program point (i.e. an @@ -134,21 +135,20 @@ void FuzzerPassConstructComposites::Apply() { // We did not manage to make a composite; return 0 to indicate that no // instructions were added. assert(constructor_arguments == nullptr); - return 0; + return; } assert(constructor_arguments != nullptr); // Make and apply a transformation. TransformationConstructComposite transformation( - chosen_composite_type, *constructor_arguments, base, offset, - GetFuzzerContext()->GetFreshId()); + chosen_composite_type, *constructor_arguments, + instruction_descriptor, GetFuzzerContext()->GetFreshId()); assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) && "This transformation should be applicable by construction."); transformation.Apply(GetIRContext(), GetFactManager()); *GetTransformations()->add_transformation() = transformation.ToMessage(); // Indicate that one instruction was added. - return 1; }); } diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.cpp index 8c85a3bad..35b15a38a 100644 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.cpp +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.cpp @@ -31,19 +31,25 @@ FuzzerPassCopyObjects::~FuzzerPassCopyObjects() = default; void FuzzerPassCopyObjects::Apply() { MaybeAddTransformationBeforeEachInstruction( [this](const opt::Function& function, opt::BasicBlock* block, - opt::BasicBlock::iterator inst_it, uint32_t base, - uint32_t offset) -> uint32_t { + opt::BasicBlock::iterator inst_it, + const protobufs::InstructionDescriptor& instruction_descriptor) + -> void { + assert(inst_it->opcode() == + instruction_descriptor.target_instruction_opcode() && + "The opcode of the instruction we might insert before must be " + "the same as the opcode in the descriptor for the instruction"); + // Check whether it is legitimate to insert a copy before this // instruction. if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyObject, inst_it)) { - return 0; + return; } // Randomly decide whether to try inserting an object copy here. if (!GetFuzzerContext()->ChoosePercentage( GetFuzzerContext()->GetChanceOfCopyingObject())) { - return 0; + return; } std::vector relevant_instructions = @@ -53,21 +59,20 @@ void FuzzerPassCopyObjects::Apply() { // At this point, |relevant_instructions| contains all the instructions // we might think of copying. if (relevant_instructions.empty()) { - return 0; + return; } // Choose a copyable instruction at random, and create and apply an // object copying transformation based on it. uint32_t index = GetFuzzerContext()->RandomIndex(relevant_instructions); TransformationCopyObject transformation( - relevant_instructions[index]->result_id(), base, offset, + relevant_instructions[index]->result_id(), instruction_descriptor, GetFuzzerContext()->GetFreshId()); assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) && "This transformation should be applicable by construction."); transformation.Apply(GetIRContext(), GetFactManager()); *GetTransformations()->add_transformation() = transformation.ToMessage(); - return 1; }); } diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp index c0318e887..6a2ea4dcc 100644 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp @@ -14,9 +14,9 @@ #include "source/fuzz/fuzzer_pass_split_blocks.h" -#include #include +#include "source/fuzz/instruction_descriptor.h" #include "source/fuzz/transformation_split_block.h" namespace spvtools { @@ -49,40 +49,49 @@ void FuzzerPassSplitBlocks::Apply() { // We are not going to try to split this block. continue; } + + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2964): consider + // taking a simpler approach to identifying the instruction before which + // to split a block. + // We are going to try to split this block. We now need to choose where - // to split it. We do this by finding a base instruction that has a - // result id, and an offset from that base instruction. We would like - // offsets to be as small as possible and ideally 0 - we only need offsets - // because not all instructions can be identified by a result id (e.g. - // OpStore instructions cannot). - std::vector> base_offset_pairs; + // to split it. We describe the instruction before which we would like to + // split a block via an InstructionDescriptor, details of which are + // commented in the protobufs definition file. + std::vector instruction_descriptors; + // The initial base instruction is the block label. uint32_t base = block->id(); - uint32_t offset = 0; + + // Counts the number of times we have seen each opcode since we reset the + // base instruction. + std::map skip_count; + // Consider every instruction in the block. The label is excluded: it is // only necessary to consider it as a base in case the first instruction // in the block does not have a result id. for (auto& inst : *block) { if (inst.HasResultId()) { // In the case that the instruction has a result id, we use the - // instruction as its own base, with zero offset. + // instruction as its own base, and clear the skip counts we have + // collected. base = inst.result_id(); - offset = 0; - } else { - // The instruction does not have a result id, so we need to identify - // it via the latest instruction that did have a result id (base), and - // an incremented offset. - offset++; + skip_count.clear(); + } + const SpvOp opcode = inst.opcode(); + instruction_descriptors.emplace_back(MakeInstructionDescriptor( + base, opcode, skip_count.count(opcode) ? skip_count.at(opcode) : 0)); + if (!inst.HasResultId()) { + skip_count[opcode] = + skip_count.count(opcode) ? skip_count.at(opcode) + 1 : 1; } - base_offset_pairs.emplace_back(base, offset); } // Having identified all the places we might be able to split the block, // we choose one of them. - auto base_offset = - base_offset_pairs[GetFuzzerContext()->RandomIndex(base_offset_pairs)]; - auto transformation = - TransformationSplitBlock(base_offset.first, base_offset.second, - GetFuzzerContext()->GetFreshId()); + auto transformation = TransformationSplitBlock( + instruction_descriptors[GetFuzzerContext()->RandomIndex( + instruction_descriptors)], + GetFuzzerContext()->GetFreshId()); // If the position we have chosen turns out to be a valid place to split // the block, we apply the split. Otherwise the block just doesn't get // split. diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp index e61ccaeb5..2374c6c47 100644 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp @@ -170,39 +170,14 @@ bool BlockIsInLoopContinueConstruct(opt::IRContext* context, uint32_t block_id, return false; } -opt::BasicBlock::iterator GetIteratorForBaseInstructionAndOffset( - opt::BasicBlock* block, const opt::Instruction* base_inst, - uint32_t offset) { - // The cases where |base_inst| is the block's label, vs. inside the block, - // are dealt with separately. - if (base_inst == block->GetLabelInst()) { - // |base_inst| is the block's label. - if (offset == 0) { - // We cannot return an iterator to the block's label. - return block->end(); - } - // Conceptually, the first instruction in the block is [label + 1]. - // We thus start from 1 when applying the offset. - auto inst_it = block->begin(); - for (uint32_t i = 1; i < offset && inst_it != block->end(); i++) { - ++inst_it; - } - // This is either the desired instruction, or the end of the block. - return inst_it; - } - // |base_inst| is inside the block. +opt::BasicBlock::iterator GetIteratorForInstruction( + opt::BasicBlock* block, const opt::Instruction* inst) { for (auto inst_it = block->begin(); inst_it != block->end(); ++inst_it) { - if (base_inst == &*inst_it) { - // We have found the base instruction; we now apply the offset. - for (uint32_t i = 0; i < offset && inst_it != block->end(); i++) { - ++inst_it; - } - // This is either the desired instruction, or the end of the block. + if (inst == &*inst_it) { return inst_it; } } - assert(false && "The base instruction was not found."); - return nullptr; + return block->end(); } bool NewEdgeRespectsUseDefDominance(opt::IRContext* context, diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_util.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_util.h index 890ceac4d..42206cad0 100644 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_util.h +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_util.h @@ -64,15 +64,10 @@ void AddUnreachableEdgeAndUpdateOpPhis( bool BlockIsInLoopContinueConstruct(opt::IRContext* context, uint32_t block_id, uint32_t maybe_loop_header_id); -// Requires that |base_inst| is either the label instruction of |block| or an -// instruction inside |block|. -// -// If the block contains a (non-label, non-terminator) instruction |offset| -// instructions after |base_inst|, an iterator to this instruction is returned. -// +// If |block| contains |inst|, an iterator for |inst| is returned. // Otherwise |block|->end() is returned. -opt::BasicBlock::iterator GetIteratorForBaseInstructionAndOffset( - opt::BasicBlock* block, const opt::Instruction* base_inst, uint32_t offset); +opt::BasicBlock::iterator GetIteratorForInstruction( + opt::BasicBlock* block, const opt::Instruction* inst); // The function determines whether adding an edge from |bb_from| to |bb_to| - // is legitimate with respect to the SPIR-V rule that a definition must diff --git a/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto b/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto index 1e4527c88..53a28f56f 100644 --- a/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto +++ b/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto @@ -331,15 +331,12 @@ message TransformationCopyObject { // Id of the object to be copied uint32 object = 1; - // The id of an instruction in a block - uint32 base_instruction_id = 2; - - // An offset, such that OpCopyObject instruction should be inserted right - // before the instruction |offset| instructions after |base_instruction_id| - uint32 offset = 3; + // A descriptor for an instruction in a block before which the new + // OpCopyObject instruction should be inserted + InstructionDescriptor instruction_to_insert_before = 2; // A fresh id for the copied object - uint32 fresh_id = 4; + uint32 fresh_id = 3; } @@ -354,16 +351,12 @@ message TransformationConstructComposite { // Ids of the objects that will form the components of the composite repeated uint32 component = 2; - // The id of an instruction in a block - uint32 base_instruction_id = 3; - - // An offset, such that OpCompositeConstruct instruction should be inserted - // right before the instruction |offset| instructions after - // |base_instruction_id| - uint32 offset = 4; + // A descriptor for an instruction in a block before which the new + // OpCompositeConstruct instruction should be inserted + InstructionDescriptor instruction_to_insert_before = 3; // A fresh id for the composite object - uint32 fresh_id = 5; + uint32 fresh_id = 4; } @@ -491,13 +484,9 @@ message TransformationSplitBlock { // A transformation that splits a basic block into two basic blocks - // The result id of an instruction - uint32 base_instruction_id = 1; - - // An offset, such that the block containing |base_instruction_id| should be - // split right before the instruction |offset| instructions after - // |base_instruction_id| - uint32 offset = 2; + // A descriptor for an instruction such that the block containing the + // described instruction should be split right before the instruction. + InstructionDescriptor instruction_to_split_before = 1; // An id that must not yet be used by the module to which this transformation // is applied. Rather than having the transformation choose a suitable id on @@ -507,6 +496,6 @@ message TransformationSplitBlock { // transformation, and if we end up changing what that id is, due to removing // earlier transformations, it may inhibit later transformations from // applying. - uint32 fresh_id = 3; + uint32 fresh_id = 2; } diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_construct_composite.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_construct_composite.cpp index 3c6c956a0..761eaecc5 100644 --- a/3rdparty/spirv-tools/source/fuzz/transformation_construct_composite.cpp +++ b/3rdparty/spirv-tools/source/fuzz/transformation_construct_composite.cpp @@ -15,6 +15,8 @@ #include "source/fuzz/transformation_construct_composite.h" #include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/instruction_descriptor.h" +#include "source/opt/instruction.h" namespace spvtools { namespace fuzz { @@ -25,13 +27,14 @@ TransformationConstructComposite::TransformationConstructComposite( TransformationConstructComposite::TransformationConstructComposite( uint32_t composite_type_id, std::vector component, - uint32_t base_instruction_id, uint32_t offset, uint32_t fresh_id) { + const protobufs::InstructionDescriptor& instruction_to_insert_before, + uint32_t fresh_id) { message_.set_composite_type_id(composite_type_id); for (auto a_component : component) { message_.add_component(a_component); } - message_.set_base_instruction_id(base_instruction_id); - message_.set_offset(offset); + *message_.mutable_instruction_to_insert_before() = + instruction_to_insert_before; message_.set_fresh_id(fresh_id); } @@ -42,24 +45,11 @@ bool TransformationConstructComposite::IsApplicable( return false; } - auto base_instruction = - context->get_def_use_mgr()->GetDef(message_.base_instruction_id()); - if (!base_instruction) { - // The given id to insert after is not defined. - return false; - } - - auto destination_block = context->get_instr_block(base_instruction); - if (!destination_block) { - // The given id to insert after is not in a block. - return false; - } - - auto insert_before = fuzzerutil::GetIteratorForBaseInstructionAndOffset( - destination_block, base_instruction, message_.offset()); - - if (insert_before == destination_block->end()) { - // The offset was inappropriate. + auto insert_before = + FindInstruction(message_.instruction_to_insert_before(), context); + if (!insert_before) { + // The instruction before which the composite should be inserted was not + // found. return false; } @@ -125,11 +115,11 @@ void TransformationConstructComposite::Apply(opt::IRContext* context, FactManager* fact_manager) const { // Use the base and offset information from the transformation to determine // where in the module a new instruction should be inserted. - auto base_instruction = - context->get_def_use_mgr()->GetDef(message_.base_instruction_id()); - auto destination_block = context->get_instr_block(base_instruction); - auto insert_before = fuzzerutil::GetIteratorForBaseInstructionAndOffset( - destination_block, base_instruction, message_.offset()); + auto insert_before_inst = + FindInstruction(message_.instruction_to_insert_before(), context); + auto destination_block = context->get_instr_block(insert_before_inst); + auto insert_before = fuzzerutil::GetIteratorForInstruction( + destination_block, insert_before_inst); // Prepare the input operands for an OpCompositeConstruct instruction. opt::Instruction::OperandList in_operands; diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_construct_composite.h b/3rdparty/spirv-tools/source/fuzz/transformation_construct_composite.h index b7124570e..8eb019116 100644 --- a/3rdparty/spirv-tools/source/fuzz/transformation_construct_composite.h +++ b/3rdparty/spirv-tools/source/fuzz/transformation_construct_composite.h @@ -28,10 +28,10 @@ class TransformationConstructComposite : public Transformation { explicit TransformationConstructComposite( const protobufs::TransformationConstructComposite& message); - TransformationConstructComposite(uint32_t composite_type_id, - std::vector component, - uint32_t base_instruction_id, - uint32_t offset, uint32_t fresh_id); + TransformationConstructComposite( + uint32_t composite_type_id, std::vector component, + const protobufs::InstructionDescriptor& instruction_to_insert_before, + uint32_t fresh_id); // - |message_.fresh_id| must not be used by the module. // - |message_.composite_type_id| must be the id of a composite type diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_copy_object.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_copy_object.cpp index 2c6c2fdcf..1082caf86 100644 --- a/3rdparty/spirv-tools/source/fuzz/transformation_copy_object.cpp +++ b/3rdparty/spirv-tools/source/fuzz/transformation_copy_object.cpp @@ -15,6 +15,7 @@ #include "source/fuzz/transformation_copy_object.h" #include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/instruction_descriptor.h" #include "source/opt/instruction.h" #include "source/util/make_unique.h" @@ -25,13 +26,13 @@ TransformationCopyObject::TransformationCopyObject( const protobufs::TransformationCopyObject& message) : message_(message) {} -TransformationCopyObject::TransformationCopyObject(uint32_t object, - uint32_t base_instruction_id, - uint32_t offset, - uint32_t fresh_id) { +TransformationCopyObject::TransformationCopyObject( + uint32_t object, + const protobufs::InstructionDescriptor& instruction_to_insert_before, + uint32_t fresh_id) { message_.set_object(object); - message_.set_base_instruction_id(base_instruction_id); - message_.set_offset(offset); + *message_.mutable_instruction_to_insert_before() = + instruction_to_insert_before; message_.set_fresh_id(fresh_id); } @@ -50,24 +51,10 @@ bool TransformationCopyObject::IsApplicable( return false; } - auto base_instruction = - context->get_def_use_mgr()->GetDef(message_.base_instruction_id()); - if (!base_instruction) { - // The given id to insert after is not defined. - return false; - } - - auto destination_block = context->get_instr_block(base_instruction); - if (!destination_block) { - // The given id to insert after is not in a block. - return false; - } - - auto insert_before = fuzzerutil::GetIteratorForBaseInstructionAndOffset( - destination_block, base_instruction, message_.offset()); - - if (insert_before == destination_block->end()) { - // The offset was inappropriate. + auto insert_before = + FindInstruction(message_.instruction_to_insert_before(), context); + if (!insert_before) { + // The instruction before which the copy should be inserted was not found. return false; } @@ -86,7 +73,9 @@ bool TransformationCopyObject::IsApplicable( // insert it before the object's defining instruction. return !context->get_instr_block(object_inst) || (object_inst != &*insert_before && - context->GetDominatorAnalysis(destination_block->GetParent()) + context + ->GetDominatorAnalysis( + context->get_instr_block(insert_before)->GetParent()) ->Dominates(object_inst, &*insert_before)); } @@ -94,13 +83,12 @@ void TransformationCopyObject::Apply(opt::IRContext* context, FactManager* fact_manager) const { auto object_inst = context->get_def_use_mgr()->GetDef(message_.object()); assert(object_inst && "The object to be copied must exist."); - auto base_instruction = - context->get_def_use_mgr()->GetDef(message_.base_instruction_id()); - assert(base_instruction && "The base instruction must exist."); - auto destination_block = context->get_instr_block(base_instruction); + auto insert_before_inst = + FindInstruction(message_.instruction_to_insert_before(), context); + auto destination_block = context->get_instr_block(insert_before_inst); assert(destination_block && "The base instruction must be in a block."); - auto insert_before = fuzzerutil::GetIteratorForBaseInstructionAndOffset( - destination_block, base_instruction, message_.offset()); + auto insert_before = fuzzerutil::GetIteratorForInstruction( + destination_block, insert_before_inst); assert(insert_before != destination_block->end() && "There must be an instruction before which the copy can be inserted."); diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_copy_object.h b/3rdparty/spirv-tools/source/fuzz/transformation_copy_object.h index 1b4272652..3a75ac9d9 100644 --- a/3rdparty/spirv-tools/source/fuzz/transformation_copy_object.h +++ b/3rdparty/spirv-tools/source/fuzz/transformation_copy_object.h @@ -28,8 +28,10 @@ class TransformationCopyObject : public Transformation { explicit TransformationCopyObject( const protobufs::TransformationCopyObject& message); - TransformationCopyObject(uint32_t object, uint32_t base_instruction_id, - uint32_t offset, uint32_t fresh_id); + TransformationCopyObject( + uint32_t object, + const protobufs::InstructionDescriptor& instruction_to_insert_before, + uint32_t fresh_id); // - |message_.fresh_id| must not be used by the module. // - |message_.object| must be a result id that is a legitimate operand for diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_split_block.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_split_block.cpp index a2da371c6..9f6da7c38 100644 --- a/3rdparty/spirv-tools/source/fuzz/transformation_split_block.cpp +++ b/3rdparty/spirv-tools/source/fuzz/transformation_split_block.cpp @@ -17,6 +17,7 @@ #include #include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/instruction_descriptor.h" #include "source/util/make_unique.h" namespace spvtools { @@ -26,11 +27,10 @@ TransformationSplitBlock::TransformationSplitBlock( const spvtools::fuzz::protobufs::TransformationSplitBlock& message) : message_(message) {} -TransformationSplitBlock::TransformationSplitBlock(uint32_t base_instruction_id, - uint32_t offset, - uint32_t fresh_id) { - message_.set_base_instruction_id(base_instruction_id); - message_.set_offset(offset); +TransformationSplitBlock::TransformationSplitBlock( + const protobufs::InstructionDescriptor& instruction_to_split_before, + uint32_t fresh_id) { + *message_.mutable_instruction_to_split_before() = instruction_to_split_before; message_.set_fresh_id(fresh_id); } @@ -40,31 +40,28 @@ bool TransformationSplitBlock::IsApplicable( // We require the id for the new block to be unused. return false; } - auto base_instruction = - context->get_def_use_mgr()->GetDef(message_.base_instruction_id()); - if (!base_instruction) { + auto instruction_to_split_before = + FindInstruction(message_.instruction_to_split_before(), context); + if (!instruction_to_split_before) { // The instruction describing the block we should split does not exist. return false; } - auto block_containing_base_instruction = - context->get_instr_block(base_instruction); - if (!block_containing_base_instruction) { - // The instruction describing the block we should split is not contained in - // a block. - return false; - } + auto block_to_split = context->get_instr_block(instruction_to_split_before); + assert(block_to_split && + "We should not have managed to find the " + "instruction if it was not contained in a block."); - if (block_containing_base_instruction->IsLoopHeader()) { + if (block_to_split->IsLoopHeader()) { // We cannot split a loop header block: back-edges would become invalid. return false; } - auto split_before = fuzzerutil::GetIteratorForBaseInstructionAndOffset( - block_containing_base_instruction, base_instruction, message_.offset()); - if (split_before == block_containing_base_instruction->end()) { - // The offset was inappropriate. - return false; - } + auto split_before = fuzzerutil::GetIteratorForInstruction( + block_to_split, instruction_to_split_before); + assert(split_before != block_to_split->end() && + "At this point we know the" + " block split point exists."); + if (split_before->PreviousNode() && split_before->PreviousNode()->opcode() == SpvOpSelectionMerge) { // We cannot split directly after a selection merge: this would separate @@ -84,44 +81,39 @@ bool TransformationSplitBlock::IsApplicable( void TransformationSplitBlock::Apply(opt::IRContext* context, FactManager* /*unused*/) const { - auto base_instruction = - context->get_def_use_mgr()->GetDef(message_.base_instruction_id()); - assert(base_instruction && "Base instruction must exist"); - auto block_containing_base_instruction = - context->get_instr_block(base_instruction); - assert(block_containing_base_instruction && - "Base instruction must be in a block"); - auto split_before = fuzzerutil::GetIteratorForBaseInstructionAndOffset( - block_containing_base_instruction, base_instruction, message_.offset()); - assert(split_before != block_containing_base_instruction->end() && + opt::Instruction* instruction_to_split_before = + FindInstruction(message_.instruction_to_split_before(), context); + opt::BasicBlock* block_to_split = + context->get_instr_block(instruction_to_split_before); + auto split_before = fuzzerutil::GetIteratorForInstruction( + block_to_split, instruction_to_split_before); + assert(split_before != block_to_split->end() && "If the transformation is applicable, we should have an " "instruction to split on."); + // We need to make sure the module's id bound is large enough to add the // fresh id. fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); // Split the block. - auto new_bb = block_containing_base_instruction->SplitBasicBlock( - context, message_.fresh_id(), split_before); + auto new_bb = block_to_split->SplitBasicBlock(context, message_.fresh_id(), + split_before); // The split does not automatically add a branch between the two parts of // the original block, so we add one. - block_containing_base_instruction->AddInstruction( - MakeUnique( - context, SpvOpBranch, 0, 0, - std::initializer_list{ - opt::Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID, - {message_.fresh_id()})})); + block_to_split->AddInstruction(MakeUnique( + context, SpvOpBranch, 0, 0, + std::initializer_list{opt::Operand( + spv_operand_type_t::SPV_OPERAND_TYPE_ID, {message_.fresh_id()})})); // If we split before OpPhi instructions, we need to update their // predecessor operand so that the block they used to be inside is now the // predecessor. - new_bb->ForEachPhiInst( - [block_containing_base_instruction](opt::Instruction* phi_inst) { - // The following assertion is a sanity check. It is guaranteed to hold - // if IsApplicable holds. - assert(phi_inst->NumInOperands() == 2 && - "We can only split a block before an OpPhi if block has exactly " - "one predecessor."); - phi_inst->SetInOperand(1, {block_containing_base_instruction->id()}); - }); + new_bb->ForEachPhiInst([block_to_split](opt::Instruction* phi_inst) { + // The following assertion is a sanity check. It is guaranteed to hold + // if IsApplicable holds. + assert(phi_inst->NumInOperands() == 2 && + "We can only split a block before an OpPhi if block has exactly " + "one predecessor."); + phi_inst->SetInOperand(1, {block_to_split->id()}); + }); // Invalidate all analyses context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); } diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_split_block.h b/3rdparty/spirv-tools/source/fuzz/transformation_split_block.h index 4a7095ac0..63dc7f52b 100644 --- a/3rdparty/spirv-tools/source/fuzz/transformation_split_block.h +++ b/3rdparty/spirv-tools/source/fuzz/transformation_split_block.h @@ -28,8 +28,9 @@ class TransformationSplitBlock : public Transformation { explicit TransformationSplitBlock( const protobufs::TransformationSplitBlock& message); - TransformationSplitBlock(uint32_t base_instruction_id, uint32_t offset, - uint32_t fresh_id); + TransformationSplitBlock( + const protobufs::InstructionDescriptor& instruction_to_split_before, + uint32_t fresh_id); // - |message_.base_instruction_id| must be the result id of an instruction // 'base' in some block 'blk'. diff --git a/3rdparty/spirv-tools/source/link/CMakeLists.txt b/3rdparty/spirv-tools/source/link/CMakeLists.txt index b8c4332b8..d3083192c 100644 --- a/3rdparty/spirv-tools/source/link/CMakeLists.txt +++ b/3rdparty/spirv-tools/source/link/CMakeLists.txt @@ -19,8 +19,6 @@ spvtools_default_compile_options(SPIRV-Tools-link) target_include_directories(SPIRV-Tools-link PUBLIC $ - $ - PUBLIC $ $ PRIVATE ${spirv-tools_BINARY_DIR} @@ -37,5 +35,12 @@ if(ENABLE_SPIRV_TOOLS_INSTALL) RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - install(EXPORT SPIRV-Tools-linkTargets DESTINATION lib/cmake) + export(EXPORT SPIRV-Tools-linkTargets FILE SPIRV-Tools-linkTargets.cmake) + + spvtools_config_package_dir(SPIRV-Tools-link PACKAGE_DIR) + install(EXPORT SPIRV-Tools-linkTargets FILE SPIRV-Tools-linkTargets.cmake + DESTINATION ${PACKAGE_DIR}) + + spvtools_generate_config_file(SPIRV-Tools-link) + install(FILES ${CMAKE_BINARY_DIR}/SPIRV-Tools-linkConfig.cmake DESTINATION ${PACKAGE_DIR}) endif(ENABLE_SPIRV_TOOLS_INSTALL) diff --git a/3rdparty/spirv-tools/source/opt/CMakeLists.txt b/3rdparty/spirv-tools/source/opt/CMakeLists.txt index bc680c6ea..0f719cb90 100644 --- a/3rdparty/spirv-tools/source/opt/CMakeLists.txt +++ b/3rdparty/spirv-tools/source/opt/CMakeLists.txt @@ -235,8 +235,6 @@ spvtools_default_compile_options(SPIRV-Tools-opt) target_include_directories(SPIRV-Tools-opt PUBLIC $ - $ - PUBLIC $ $ PRIVATE ${spirv-tools_BINARY_DIR} @@ -253,5 +251,12 @@ if(ENABLE_SPIRV_TOOLS_INSTALL) RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - install(EXPORT SPIRV-Tools-optTargets DESTINATION lib/cmake) + export(EXPORT SPIRV-Tools-optTargets FILE SPIRV-Tools-optTargets.cmake) + + spvtools_config_package_dir(SPIRV-Tools-opt PACKAGE_DIR) + install(EXPORT SPIRV-Tools-optTargets FILE SPIRV-Tools-optTargets.cmake + DESTINATION ${PACKAGE_DIR}) + + spvtools_generate_config_file(SPIRV-Tools-opt) + install(FILES ${CMAKE_BINARY_DIR}/SPIRV-Tools-optConfig.cmake DESTINATION ${PACKAGE_DIR}) endif(ENABLE_SPIRV_TOOLS_INSTALL) diff --git a/3rdparty/spirv-tools/source/opt/fold.cpp b/3rdparty/spirv-tools/source/opt/fold.cpp index 94f5e73fd..6550fb4fd 100644 --- a/3rdparty/spirv-tools/source/opt/fold.cpp +++ b/3rdparty/spirv-tools/source/opt/fold.cpp @@ -56,6 +56,10 @@ uint32_t InstructionFolder::UnaryOperate(SpvOp opcode, uint32_t operand) const { return ~operand; case SpvOp::SpvOpLogicalNot: return !static_cast(operand); + case SpvOp::SpvOpUConvert: + return operand; + case SpvOp::SpvOpSConvert: + return operand; default: assert(false && "Unsupported unary operation for OpSpecConstantOp instruction"); @@ -596,6 +600,8 @@ bool InstructionFolder::IsFoldableOpcode(SpvOp opcode) const { case SpvOp::SpvOpSMod: case SpvOp::SpvOpSNegate: case SpvOp::SpvOpSRem: + case SpvOp::SpvOpSConvert: + case SpvOp::SpvOpUConvert: case SpvOp::SpvOpUDiv: case SpvOp::SpvOpUGreaterThan: case SpvOp::SpvOpUGreaterThanEqual: diff --git a/3rdparty/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp b/3rdparty/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp index 56d0137f3..8ab717ea8 100644 --- a/3rdparty/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp @@ -316,6 +316,59 @@ bool IsValidTypeForComponentWiseOperation(const analysis::Type* type) { } return false; } + +// Encodes the integer |value| of in a word vector format appropriate for +// representing this value as a operands for a constant definition. Performs +// zero-extension/sign-extension/truncation when needed, based on the signess of +// the given target type. +// +// Note: type |type| argument must be either Integer or Bool. +utils::SmallVector EncodeIntegerAsWords(const analysis::Type& type, + uint32_t value) { + const uint32_t all_ones = ~0; + uint32_t bit_width = 0; + uint32_t pad_value = 0; + bool result_type_signed = false; + if (auto* int_ty = type.AsInteger()) { + bit_width = int_ty->width(); + result_type_signed = int_ty->IsSigned(); + if (result_type_signed && static_cast(value) < 0) { + pad_value = all_ones; + } + } else if (type.AsBool()) { + bit_width = 1; + } else { + assert(false && "type must be Integer or Bool"); + } + + assert(bit_width > 0); + uint32_t first_word = value; + const uint32_t bits_per_word = 32; + + // Truncate first_word if the |type| has width less than uint32. + if (bit_width < bits_per_word) { + const uint32_t num_high_bits_to_mask = bits_per_word - bit_width; + const bool is_negative_after_truncation = + result_type_signed && + utils::IsBitAtPositionSet(first_word, bit_width - 1); + + if (is_negative_after_truncation) { + // Truncate and sign-extend |first_word|. No padding words will be + // added and |pad_value| can be left as-is. + first_word = utils::SetHighBits(first_word, num_high_bits_to_mask); + } else { + first_word = utils::ClearHighBits(first_word, num_high_bits_to_mask); + } + } + + utils::SmallVector words = {first_word}; + for (uint32_t current_bit = bits_per_word; current_bit < bit_width; + current_bit += bits_per_word) { + words.push_back(pad_value); + } + + return words; +} } // namespace Instruction* FoldSpecConstantOpAndCompositePass::DoComponentWiseOperation( @@ -345,10 +398,10 @@ Instruction* FoldSpecConstantOpAndCompositePass::DoComponentWiseOperation( if (result_type->AsInteger() || result_type->AsBool()) { // Scalar operation - uint32_t result_val = + const uint32_t result_val = context()->get_instruction_folder().FoldScalars(spec_opcode, operands); - auto result_const = - context()->get_constant_mgr()->GetConstant(result_type, {result_val}); + auto result_const = context()->get_constant_mgr()->GetConstant( + result_type, EncodeIntegerAsWords(*result_type, result_val)); return context()->get_constant_mgr()->BuildInstructionAndAddToModule( result_const, pos); } else if (result_type->AsVector()) { @@ -360,9 +413,9 @@ Instruction* FoldSpecConstantOpAndCompositePass::DoComponentWiseOperation( context()->get_instruction_folder().FoldVectors(spec_opcode, num_dims, operands); std::vector result_vector_components; - for (uint32_t r : result_vec) { - if (auto rc = - context()->get_constant_mgr()->GetConstant(element_type, {r})) { + for (const uint32_t r : result_vec) { + if (auto rc = context()->get_constant_mgr()->GetConstant( + element_type, EncodeIntegerAsWords(*element_type, r))) { result_vector_components.push_back(rc); if (!context()->get_constant_mgr()->BuildInstructionAndAddToModule( rc, pos)) { diff --git a/3rdparty/spirv-tools/source/opt/folding_rules.cpp b/3rdparty/spirv-tools/source/opt/folding_rules.cpp index d2d029d73..e54a0cd56 100644 --- a/3rdparty/spirv-tools/source/opt/folding_rules.cpp +++ b/3rdparty/spirv-tools/source/opt/folding_rules.cpp @@ -1407,20 +1407,6 @@ FoldingRule CompositeExtractFeedingConstruct() { }; } -// Folds an OpCompositeExtract instruction with no indexes into an OpCopyObject. -bool ExtractWithNoIndexes(IRContext*, Instruction* inst, - const std::vector&) { - assert(inst->opcode() == SpvOpCompositeExtract && - "Wrong opcode. Should be OpCompositeExtract."); - - if (inst->NumInOperands() > 1) { - return false; - } - - inst->SetOpcode(SpvOpCopyObject); - return true; -} - FoldingRule InsertFeedingExtract() { return [](IRContext* context, Instruction* inst, const std::vector&) { @@ -2227,7 +2213,6 @@ void FoldingRules::AddFoldingRules() { // Take that into consideration. rules_[SpvOpCompositeConstruct].push_back(CompositeExtractFeedingConstruct()); - rules_[SpvOpCompositeExtract].push_back(ExtractWithNoIndexes); rules_[SpvOpCompositeExtract].push_back(InsertFeedingExtract()); rules_[SpvOpCompositeExtract].push_back(CompositeConstructFeedingExtract()); rules_[SpvOpCompositeExtract].push_back(VectorShuffleFeedingExtract()); diff --git a/3rdparty/spirv-tools/source/opt/optimizer.cpp b/3rdparty/spirv-tools/source/opt/optimizer.cpp index 1e7df9917..b9db4c6c8 100644 --- a/3rdparty/spirv-tools/source/opt/optimizer.cpp +++ b/3rdparty/spirv-tools/source/opt/optimizer.cpp @@ -565,8 +565,11 @@ bool Optimizer::Run(const uint32_t* original_binary, #ifndef NDEBUG if (status == opt::Pass::Status::SuccessWithoutChange) { - auto changed = optimized_binary->size() != original_binary_size || - memcmp(optimized_binary->data(), original_binary, + std::vector optimized_binary_with_nop; + context->module()->ToBinary(&optimized_binary_with_nop, + /* skip_nop = */ false); + auto changed = optimized_binary_with_nop.size() != original_binary_size || + memcmp(optimized_binary_with_nop.data(), original_binary, original_binary_size) != 0; assert(!changed && "Binary unexpectedly changed despite optimizer saying there was no " diff --git a/3rdparty/spirv-tools/source/reduce/CMakeLists.txt b/3rdparty/spirv-tools/source/reduce/CMakeLists.txt index 00909ee30..51e9b1d0f 100644 --- a/3rdparty/spirv-tools/source/reduce/CMakeLists.txt +++ b/3rdparty/spirv-tools/source/reduce/CMakeLists.txt @@ -79,8 +79,6 @@ spvtools_default_compile_options(SPIRV-Tools-reduce) target_include_directories(SPIRV-Tools-reduce PUBLIC $ - $ - PUBLIC $ $ PRIVATE ${spirv-tools_BINARY_DIR} @@ -98,5 +96,12 @@ if(ENABLE_SPIRV_TOOLS_INSTALL) RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - install(EXPORT SPIRV-Tools-reduceTargets DESTINATION lib/cmake) + export(EXPORT SPIRV-Tools-reduceTargets FILE SPIRV-Tools-reduceTarget.cmake) + + spvtools_config_package_dir(SPIRV-Tools-reduce PACKAGE_DIR) + install(EXPORT SPIRV-Tools-reduceTargets FILE SPIRV-Tools-reduceTarget.cmake + DESTINATION ${PACKAGE_DIR}) + + spvtools_generate_config_file(SPIRV-Tools-reduce) + install(FILES ${CMAKE_BINARY_DIR}/SPIRV-Tools-reduceConfig.cmake DESTINATION ${PACKAGE_DIR}) endif(ENABLE_SPIRV_TOOLS_INSTALL) diff --git a/3rdparty/spirv-tools/source/text.cpp b/3rdparty/spirv-tools/source/text.cpp index 5b51845c7..d88d4f7f6 100644 --- a/3rdparty/spirv-tools/source/text.cpp +++ b/3rdparty/spirv-tools/source/text.cpp @@ -810,7 +810,8 @@ spv_result_t spvTextToBinaryWithOptions(const spv_const_context context, } void spvTextDestroy(spv_text text) { - if (!text) return; - delete[] text->str; - delete text; + if (text) { + if (text->str) delete[] text->str; + delete text; + } } diff --git a/3rdparty/spirv-tools/source/util/bitutils.h b/3rdparty/spirv-tools/source/util/bitutils.h index 17d61df90..9ced2f962 100644 --- a/3rdparty/spirv-tools/source/util/bitutils.h +++ b/3rdparty/spirv-tools/source/util/bitutils.h @@ -15,8 +15,10 @@ #ifndef SOURCE_UTIL_BITUTILS_H_ #define SOURCE_UTIL_BITUTILS_H_ +#include #include #include +#include namespace spvtools { namespace utils { @@ -31,6 +33,14 @@ Dest BitwiseCast(Src source) { return dest; } +// Calculates the bit width of the integer type |T|. +template +struct IntegerBitWidth { + static_assert(std::is_integral::value, "Integer type required"); + static const size_t kBitsPerByte = 8; + static const size_t get = sizeof(T) * kBitsPerByte; +}; + // SetBits returns an integer of type with bits set // for position through , counting from the least // significant bit. In particular when Num == 0, no positions are set to 1. @@ -38,7 +48,7 @@ Dest BitwiseCast(Src source) { // a bit that will not fit in the underlying type is set. template struct SetBits { - static_assert(First < sizeof(T) * 8, + static_assert(First < IntegerBitWidth::get, "Tried to set a bit that is shifted too far."); const static T get = (T(1) << First) | SetBits::get; }; @@ -49,6 +59,11 @@ struct SetBits { }; // This is all compile-time so we can put our tests right here. +static_assert(IntegerBitWidth::get == 32, "IntegerBitWidth mismatch"); +static_assert(IntegerBitWidth::get == 32, "IntegerBitWidth mismatch"); +static_assert(IntegerBitWidth::get == 64, "IntegerBitWidth mismatch"); +static_assert(IntegerBitWidth::get == 8, "IntegerBitWidth mismatch"); + static_assert(SetBits::get == uint32_t(0x00000000), "SetBits failed"); static_assert(SetBits::get == uint32_t(0x00000001), @@ -90,6 +105,82 @@ size_t CountSetBits(T word) { return count; } +// Checks if the bit at the |position| is set to '1'. +// Bits zero-indexed starting at the least significant bit. +// |position| must be within the bit width of |T|. +template +bool IsBitAtPositionSet(T word, size_t position) { + static_assert(std::is_integral::value, "Integer type required"); + static_assert(std::is_unsigned::value, "Unsigned type required"); + assert(position < IntegerBitWidth::get && + "position must be less than the bit width"); + return word & T(T(1) << position); +} + +// Returns a value obtained by setting a range of adjacent bits of |word| to +// |value|. Affected bits are within the range: +// [first_position, first_position + num_bits_to_mutate), +// assuming zero-based indexing starting at the least +// significant bit. Bits to mutate must be within the bit width of |T|. +template +T MutateBits(T word, size_t first_position, size_t num_bits_to_mutate, + bool value) { + static_assert(std::is_integral::value, "Integer type required"); + static_assert(std::is_unsigned::value, "Unsigned type required"); + static const size_t word_bit_width = IntegerBitWidth::get; + assert(first_position < word_bit_width && + "Mutated bits must be within bit width"); + assert(first_position + num_bits_to_mutate <= word_bit_width && + "Mutated bits must be within bit width"); + if (num_bits_to_mutate == 0) { + return word; + } + + const T all_ones = ~T(0); + const size_t num_unaffected_low_bits = first_position; + const T unaffected_low_mask = + T(T(all_ones >> num_unaffected_low_bits) << num_unaffected_low_bits); + + const size_t num_unaffected_high_bits = + word_bit_width - (first_position + num_bits_to_mutate); + const T unaffected_high_mask = + T(T(all_ones << num_unaffected_high_bits) >> num_unaffected_high_bits); + + const T mutation_mask = unaffected_low_mask & unaffected_high_mask; + if (value) { + return word | mutation_mask; + } + return word & T(~mutation_mask); +} + +// Returns a value obtained by setting the |num_bits_to_set| highest bits to +// '1'. |num_bits_to_set| must be not be greater than the bit width of |T|. +template +T SetHighBits(T word, size_t num_bits_to_set) { + if (num_bits_to_set == 0) { + return word; + } + const size_t word_bit_width = IntegerBitWidth::get; + assert(num_bits_to_set <= word_bit_width && + "Can't set more bits than bit width"); + return MutateBits(word, word_bit_width - num_bits_to_set, num_bits_to_set, + true); +} + +// Returns a value obtained by setting the |num_bits_to_set| highest bits to +// '0'. |num_bits_to_set| must be not be greater than the bit width of |T|. +template +T ClearHighBits(T word, size_t num_bits_to_set) { + if (num_bits_to_set == 0) { + return word; + } + const size_t word_bit_width = IntegerBitWidth::get; + assert(num_bits_to_set <= word_bit_width && + "Can't clear more bits than bit width"); + return MutateBits(word, word_bit_width - num_bits_to_set, num_bits_to_set, + false); +} + } // namespace utils } // namespace spvtools diff --git a/3rdparty/spirv-tools/source/val/validate_composites.cpp b/3rdparty/spirv-tools/source/val/validate_composites.cpp index 9b7f592bf..eb8a3244a 100644 --- a/3rdparty/spirv-tools/source/val/validate_composites.cpp +++ b/3rdparty/spirv-tools/source/val/validate_composites.cpp @@ -30,8 +30,8 @@ namespace { // OpCompositeInsert instruction. The function traverses the hierarchy of // nested data structures (structs, arrays, vectors, matrices) as directed by // the sequence of indices in the instruction. May return error if traversal -// fails (encountered non-composite, out of bounds, nesting too deep). -// Returns the type of Composite operand if the instruction has no indices. +// fails (encountered non-composite, out of bounds, no indices, nesting too +// deep). spv_result_t GetExtractInsertValueType(ValidationState_t& _, const Instruction* inst, uint32_t* member_type) { @@ -40,10 +40,15 @@ spv_result_t GetExtractInsertValueType(ValidationState_t& _, uint32_t word_index = opcode == SpvOpCompositeExtract ? 4 : 5; const uint32_t num_words = static_cast(inst->words().size()); const uint32_t composite_id_index = word_index - 1; - const uint32_t num_indices = num_words - word_index; const uint32_t kCompositeExtractInsertMaxNumIndices = 255; - if (num_indices > kCompositeExtractInsertMaxNumIndices) { + + if (num_indices == 0) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected at least one index to Op" + << spvOpcodeString(inst->opcode()) << ", zero found"; + + } else if (num_indices > kCompositeExtractInsertMaxNumIndices) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "The number of indexes in Op" << spvOpcodeString(opcode) << " may not exceed " << kCompositeExtractInsertMaxNumIndices @@ -386,20 +391,20 @@ spv_result_t ValidateCompositeExtract(ValidationState_t& _, return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Cannot extract from a composite of 8- or 16-bit types"; } + return SPV_SUCCESS; } spv_result_t ValidateCompositeInsert(ValidationState_t& _, const Instruction* inst) { - const SpvOp opcode = inst->opcode(); const uint32_t object_type = _.GetOperandTypeId(inst, 2); const uint32_t composite_type = _.GetOperandTypeId(inst, 3); const uint32_t result_type = inst->type_id(); if (result_type != composite_type) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "The Result Type must be the same as Composite type in Op" - << spvOpcodeString(opcode) << " yielding Result Id " << result_type - << "."; + << spvOpcodeString(inst->opcode()) << " yielding Result Id " + << result_type << "."; } uint32_t member_type = 0; @@ -421,6 +426,7 @@ spv_result_t ValidateCompositeInsert(ValidationState_t& _, return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Cannot insert into a composite of 8- or 16-bit types"; } + return SPV_SUCCESS; } diff --git a/3rdparty/spirv-tools/source/val/validate_derivatives.cpp b/3rdparty/spirv-tools/source/val/validate_derivatives.cpp index b3f046ab7..067cc964c 100644 --- a/3rdparty/spirv-tools/source/val/validate_derivatives.cpp +++ b/3rdparty/spirv-tools/source/val/validate_derivatives.cpp @@ -46,6 +46,10 @@ spv_result_t DerivativesPass(ValidationState_t& _, const Instruction* inst) { << "Expected Result Type to be float scalar or vector type: " << spvOpcodeString(opcode); } + if (!_.ContainsSizedIntOrFloatType(result_type, SpvOpTypeFloat, 32)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Result type component width must be 32 bits"; + } const uint32_t p_type = _.GetOperandTypeId(inst, 2); if (p_type != result_type) { diff --git a/3rdparty/spirv-tools/test/binary_header_get_test.cpp b/3rdparty/spirv-tools/test/binary_header_get_test.cpp index dcaf9928a..f8f6bdbd8 100644 --- a/3rdparty/spirv-tools/test/binary_header_get_test.cpp +++ b/3rdparty/spirv-tools/test/binary_header_get_test.cpp @@ -51,7 +51,8 @@ TEST_F(BinaryHeaderGet, Default) { ASSERT_EQ(SPV_SUCCESS, spvBinaryHeaderGet(&const_bin, endian, &header)); ASSERT_EQ(static_cast(SpvMagicNumber), header.magic); - ASSERT_EQ(0x00010400u, header.version); + // Expect SPIRV-Headers updated to SPIR-V 1.5. + ASSERT_EQ(0x00010500u, header.version); ASSERT_EQ(static_cast(SPV_GENERATOR_CODEPLAY), header.generator); ASSERT_EQ(1u, header.bound); ASSERT_EQ(0u, header.schema); diff --git a/3rdparty/spirv-tools/test/fuzz/transformation_construct_composite_test.cpp b/3rdparty/spirv-tools/test/fuzz/transformation_construct_composite_test.cpp index 26988fbd1..b9e10a907 100644 --- a/3rdparty/spirv-tools/test/fuzz/transformation_construct_composite_test.cpp +++ b/3rdparty/spirv-tools/test/fuzz/transformation_construct_composite_test.cpp @@ -14,6 +14,7 @@ #include "source/fuzz/transformation_construct_composite.h" #include "source/fuzz/data_descriptor.h" +#include "source/fuzz/instruction_descriptor.h" #include "test/fuzz/fuzz_test_util.h" namespace spvtools { @@ -144,11 +145,13 @@ TEST(TransformationConstructCompositeTest, ConstructArrays) { FactManager fact_manager; // Make a vec2[3] - TransformationConstructComposite make_vec2_array_length_3(37, {41, 45, 27}, - 46, 0, 200); + TransformationConstructComposite make_vec2_array_length_3( + 37, {41, 45, 27}, MakeInstructionDescriptor(46, SpvOpAccessChain, 0), + 200); // Bad: there are too many components TransformationConstructComposite make_vec2_array_length_3_bad( - 37, {41, 45, 27, 27}, 46, 0, 200); + 37, {41, 45, 27, 27}, MakeInstructionDescriptor(46, SpvOpAccessChain, 0), + 200); ASSERT_TRUE( make_vec2_array_length_3.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE( @@ -160,11 +163,11 @@ TEST(TransformationConstructCompositeTest, ConstructArrays) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 27, 200, {2})); // Make a float[2] - TransformationConstructComposite make_float_array_length_2(9, {24, 40}, 71, 1, - 201); + TransformationConstructComposite make_float_array_length_2( + 9, {24, 40}, MakeInstructionDescriptor(71, SpvOpStore, 0), 201); // Bad: %41 does not have type float - TransformationConstructComposite make_float_array_length_2_bad(9, {41, 40}, - 71, 1, 201); + TransformationConstructComposite make_float_array_length_2_bad( + 9, {41, 40}, MakeInstructionDescriptor(71, SpvOpStore, 0), 201); ASSERT_TRUE( make_float_array_length_2.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE( @@ -175,11 +178,13 @@ TEST(TransformationConstructCompositeTest, ConstructArrays) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 40, 201, {1})); // Make a bool[3] - TransformationConstructComposite make_bool_array_length_3(47, {33, 50, 50}, - 33, 1, 202); + TransformationConstructComposite make_bool_array_length_3( + 47, {33, 50, 50}, MakeInstructionDescriptor(33, SpvOpSelectionMerge, 0), + 202); // Bad: %54 is not available at the desired program point. TransformationConstructComposite make_bool_array_length_3_bad( - 47, {33, 54, 50}, 33, 1, 202); + 47, {33, 54, 50}, MakeInstructionDescriptor(33, SpvOpSelectionMerge, 0), + 202); ASSERT_TRUE( make_bool_array_length_3.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE( @@ -191,11 +196,11 @@ TEST(TransformationConstructCompositeTest, ConstructArrays) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 50, 202, {2})); // make a uvec3[2][2] - TransformationConstructComposite make_uvec3_array_length_2_2(58, {69, 100}, - 64, 1, 203); - // Bad: Offset 100 is too large. + TransformationConstructComposite make_uvec3_array_length_2_2( + 58, {69, 100}, MakeInstructionDescriptor(64, SpvOpStore, 0), 203); + // Bad: Skip count 100 is too large. TransformationConstructComposite make_uvec3_array_length_2_2_bad( - 58, {33, 54}, 64, 100, 203); + 58, {33, 54}, MakeInstructionDescriptor(64, SpvOpStore, 100), 203); ASSERT_TRUE( make_uvec3_array_length_2_2.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_uvec3_array_length_2_2_bad.IsApplicable(context.get(), @@ -393,9 +398,11 @@ TEST(TransformationConstructCompositeTest, ConstructMatrices) { FactManager fact_manager; // make a mat3x4 - TransformationConstructComposite make_mat34(32, {25, 28, 31}, 31, 2, 200); + TransformationConstructComposite make_mat34( + 32, {25, 28, 31}, MakeInstructionDescriptor(31, SpvOpReturn, 0), 200); // Bad: %35 is mat4x3, not mat3x4. - TransformationConstructComposite make_mat34_bad(35, {25, 28, 31}, 31, 2, 200); + TransformationConstructComposite make_mat34_bad( + 35, {25, 28, 31}, MakeInstructionDescriptor(31, SpvOpReturn, 0), 200); ASSERT_TRUE(make_mat34.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_mat34_bad.IsApplicable(context.get(), fact_manager)); make_mat34.Apply(context.get(), &fact_manager); @@ -405,11 +412,11 @@ TEST(TransformationConstructCompositeTest, ConstructMatrices) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 31, 200, {2})); // make a mat4x3 - TransformationConstructComposite make_mat43(35, {11, 13, 16, 100}, 31, 1, - 201); + TransformationConstructComposite make_mat43( + 35, {11, 13, 16, 100}, MakeInstructionDescriptor(31, SpvOpStore, 0), 201); // Bad: %25 does not match the matrix's column type. - TransformationConstructComposite make_mat43_bad(35, {25, 13, 16, 100}, 31, 1, - 201); + TransformationConstructComposite make_mat43_bad( + 35, {25, 13, 16, 100}, MakeInstructionDescriptor(31, SpvOpStore, 0), 201); ASSERT_TRUE(make_mat43.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_mat43_bad.IsApplicable(context.get(), fact_manager)); make_mat43.Apply(context.get(), &fact_manager); @@ -592,9 +599,11 @@ TEST(TransformationConstructCompositeTest, ConstructStructs) { FactManager fact_manager; // make an Inner - TransformationConstructComposite make_inner(9, {25, 19}, 57, 0, 200); + TransformationConstructComposite make_inner( + 9, {25, 19}, MakeInstructionDescriptor(57, SpvOpAccessChain, 0), 200); // Bad: Too few fields to make the struct. - TransformationConstructComposite make_inner_bad(9, {25}, 57, 0, 200); + TransformationConstructComposite make_inner_bad( + 9, {25}, MakeInstructionDescriptor(57, SpvOpAccessChain, 0), 200); ASSERT_TRUE(make_inner.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_inner_bad.IsApplicable(context.get(), fact_manager)); make_inner.Apply(context.get(), &fact_manager); @@ -603,10 +612,13 @@ TEST(TransformationConstructCompositeTest, ConstructStructs) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 19, 200, {1})); // make an Outer - TransformationConstructComposite make_outer(33, {46, 200, 56}, 200, 1, 201); + TransformationConstructComposite make_outer( + 33, {46, 200, 56}, MakeInstructionDescriptor(200, SpvOpAccessChain, 0), + 201); // Bad: %200 is not available at the desired program point. - TransformationConstructComposite make_outer_bad(33, {46, 200, 56}, 200, 0, - 201); + TransformationConstructComposite make_outer_bad( + 33, {46, 200, 56}, + MakeInstructionDescriptor(200, SpvOpCompositeConstruct, 0), 201); ASSERT_TRUE(make_outer.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_outer_bad.IsApplicable(context.get(), fact_manager)); make_outer.Apply(context.get(), &fact_manager); @@ -900,9 +912,11 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { FactManager fact_manager; - TransformationConstructComposite make_vec2(7, {17, 11}, 100, 1, 200); + TransformationConstructComposite make_vec2( + 7, {17, 11}, MakeInstructionDescriptor(100, SpvOpStore, 0), 200); // Bad: not enough data for a vec2 - TransformationConstructComposite make_vec2_bad(7, {11}, 100, 1, 200); + TransformationConstructComposite make_vec2_bad( + 7, {11}, MakeInstructionDescriptor(100, SpvOpStore, 0), 200); ASSERT_TRUE(make_vec2.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_vec2_bad.IsApplicable(context.get(), fact_manager)); make_vec2.Apply(context.get(), &fact_manager); @@ -910,9 +924,13 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 17, 200, {0})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 11, 200, {1})); - TransformationConstructComposite make_vec3(25, {12, 32}, 35, 0, 201); + TransformationConstructComposite make_vec3( + 25, {12, 32}, MakeInstructionDescriptor(35, SpvOpCompositeConstruct, 0), + 201); // Bad: too much data for a vec3 - TransformationConstructComposite make_vec3_bad(25, {12, 32, 32}, 35, 0, 201); + TransformationConstructComposite make_vec3_bad( + 25, {12, 32, 32}, + MakeInstructionDescriptor(35, SpvOpCompositeConstruct, 0), 201); ASSERT_TRUE(make_vec3.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_vec3_bad.IsApplicable(context.get(), fact_manager)); make_vec3.Apply(context.get(), &fact_manager); @@ -920,10 +938,13 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 12, 201, {0})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 32, 201, {2})); - TransformationConstructComposite make_vec4(44, {32, 32, 10, 11}, 75, 0, 202); + TransformationConstructComposite make_vec4( + 44, {32, 32, 10, 11}, MakeInstructionDescriptor(75, SpvOpAccessChain, 0), + 202); // Bad: id 48 is not available at the insertion points - TransformationConstructComposite make_vec4_bad(44, {48, 32, 10, 11}, 75, 0, - 202); + TransformationConstructComposite make_vec4_bad( + 44, {48, 32, 10, 11}, MakeInstructionDescriptor(75, SpvOpAccessChain, 0), + 202); ASSERT_TRUE(make_vec4.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_vec4_bad.IsApplicable(context.get(), fact_manager)); make_vec4.Apply(context.get(), &fact_manager); @@ -933,9 +954,11 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 10, 202, {2})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 11, 202, {3})); - TransformationConstructComposite make_ivec2(51, {126, 120}, 128, 0, 203); + TransformationConstructComposite make_ivec2( + 51, {126, 120}, MakeInstructionDescriptor(128, SpvOpLoad, 0), 203); // Bad: if 128 is not available at the instruction that defines 128 - TransformationConstructComposite make_ivec2_bad(51, {128, 120}, 128, 0, 203); + TransformationConstructComposite make_ivec2_bad( + 51, {128, 120}, MakeInstructionDescriptor(128, SpvOpLoad, 0), 203); ASSERT_TRUE(make_ivec2.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_ivec2_bad.IsApplicable(context.get(), fact_manager)); make_ivec2.Apply(context.get(), &fact_manager); @@ -943,10 +966,13 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 126, 203, {0})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 120, 203, {1})); - TransformationConstructComposite make_ivec3(114, {56, 117, 56}, 66, 1, 204); + TransformationConstructComposite make_ivec3( + 114, {56, 117, 56}, MakeInstructionDescriptor(66, SpvOpAccessChain, 0), + 204); // Bad because 1300 is not an id - TransformationConstructComposite make_ivec3_bad(114, {56, 117, 1300}, 66, 1, - 204); + TransformationConstructComposite make_ivec3_bad( + 114, {56, 117, 1300}, MakeInstructionDescriptor(66, SpvOpAccessChain, 0), + 204); ASSERT_TRUE(make_ivec3.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_ivec3_bad.IsApplicable(context.get(), fact_manager)); make_ivec3.Apply(context.get(), &fact_manager); @@ -955,11 +981,13 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 117, 204, {1})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 56, 204, {2})); - TransformationConstructComposite make_ivec4(122, {56, 117, 117, 117}, 66, 0, - 205); + TransformationConstructComposite make_ivec4( + 122, {56, 117, 117, 117}, MakeInstructionDescriptor(66, SpvOpIAdd, 0), + 205); // Bad because 86 is the wrong type. - TransformationConstructComposite make_ivec4_bad(86, {56, 117, 117, 117}, 66, - 0, 205); + TransformationConstructComposite make_ivec4_bad( + 86, {56, 117, 117, 117}, MakeInstructionDescriptor(66, SpvOpIAdd, 0), + 205); ASSERT_TRUE(make_ivec4.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_ivec4_bad.IsApplicable(context.get(), fact_manager)); make_ivec4.Apply(context.get(), &fact_manager); @@ -969,8 +997,10 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 117, 205, {2})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 117, 205, {3})); - TransformationConstructComposite make_uvec2(86, {18, 38}, 133, 2, 206); - TransformationConstructComposite make_uvec2_bad(86, {18, 38}, 133, 200, 206); + TransformationConstructComposite make_uvec2( + 86, {18, 38}, MakeInstructionDescriptor(133, SpvOpAccessChain, 0), 206); + TransformationConstructComposite make_uvec2_bad( + 86, {18, 38}, MakeInstructionDescriptor(133, SpvOpAccessChain, 200), 206); ASSERT_TRUE(make_uvec2.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_uvec2_bad.IsApplicable(context.get(), fact_manager)); make_uvec2.Apply(context.get(), &fact_manager); @@ -978,10 +1008,11 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 18, 206, {0})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 38, 206, {1})); - TransformationConstructComposite make_uvec3(59, {14, 18, 136}, 137, 2, 207); + TransformationConstructComposite make_uvec3( + 59, {14, 18, 136}, MakeInstructionDescriptor(137, SpvOpReturn, 0), 207); // Bad because 1300 is not an id - TransformationConstructComposite make_uvec3_bad(59, {14, 18, 1300}, 137, 2, - 207); + TransformationConstructComposite make_uvec3_bad( + 59, {14, 18, 1300}, MakeInstructionDescriptor(137, SpvOpReturn, 0), 207); ASSERT_TRUE(make_uvec3.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_uvec3_bad.IsApplicable(context.get(), fact_manager)); make_uvec3.Apply(context.get(), &fact_manager); @@ -990,11 +1021,13 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 18, 207, {1})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 136, 207, {2})); - TransformationConstructComposite make_uvec4(131, {14, 18, 136, 136}, 137, 0, - 208); + TransformationConstructComposite make_uvec4( + 131, {14, 18, 136, 136}, + MakeInstructionDescriptor(137, SpvOpAccessChain, 0), 208); // Bad because 86 is the wrong type. - TransformationConstructComposite make_uvec4_bad(86, {14, 18, 136, 136}, 137, - 0, 208); + TransformationConstructComposite make_uvec4_bad( + 86, {14, 18, 136, 136}, + MakeInstructionDescriptor(137, SpvOpAccessChain, 0), 208); ASSERT_TRUE(make_uvec4.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_uvec4_bad.IsApplicable(context.get(), fact_manager)); make_uvec4.Apply(context.get(), &fact_manager); @@ -1004,19 +1037,21 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 136, 208, {2})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 136, 208, {3})); - TransformationConstructComposite make_bvec2(102, - { - 111, - 41, - }, - 75, 0, 209); + TransformationConstructComposite make_bvec2( + 102, + { + 111, + 41, + }, + MakeInstructionDescriptor(75, SpvOpAccessChain, 0), 209); // Bad because 0 is not a valid base instruction id - TransformationConstructComposite make_bvec2_bad(102, - { - 111, - 41, - }, - 0, 0, 209); + TransformationConstructComposite make_bvec2_bad( + 102, + { + 111, + 41, + }, + MakeInstructionDescriptor(0, SpvOpExtInstImport, 0), 209); ASSERT_TRUE(make_bvec2.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_bvec2_bad.IsApplicable(context.get(), fact_manager)); make_bvec2.Apply(context.get(), &fact_manager); @@ -1024,9 +1059,11 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 111, 209, {0})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 41, 209, {1})); - TransformationConstructComposite make_bvec3(93, {108, 73}, 108, 1, 210); + TransformationConstructComposite make_bvec3( + 93, {108, 73}, MakeInstructionDescriptor(108, SpvOpStore, 0), 210); // Bad because there are too many components for a bvec3 - TransformationConstructComposite make_bvec3_bad(93, {108, 108}, 108, 1, 210); + TransformationConstructComposite make_bvec3_bad( + 93, {108, 108}, MakeInstructionDescriptor(108, SpvOpStore, 0), 210); ASSERT_TRUE(make_bvec3.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_bvec3_bad.IsApplicable(context.get(), fact_manager)); make_bvec3.Apply(context.get(), &fact_manager); @@ -1034,9 +1071,11 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 108, 210, {0})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 73, 210, {2})); - TransformationConstructComposite make_bvec4(70, {108, 108}, 108, 3, 211); + TransformationConstructComposite make_bvec4( + 70, {108, 108}, MakeInstructionDescriptor(108, SpvOpBranch, 0), 211); // Bad because 21 is a type, not a result id - TransformationConstructComposite make_bvec4_bad(70, {21, 108}, 108, 3, 211); + TransformationConstructComposite make_bvec4_bad( + 70, {21, 108}, MakeInstructionDescriptor(108, SpvOpBranch, 0), 211); ASSERT_TRUE(make_bvec4.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_bvec4_bad.IsApplicable(context.get(), fact_manager)); make_bvec4.Apply(context.get(), &fact_manager); diff --git a/3rdparty/spirv-tools/test/fuzz/transformation_copy_object_test.cpp b/3rdparty/spirv-tools/test/fuzz/transformation_copy_object_test.cpp index 0c214c859..25e235d7d 100644 --- a/3rdparty/spirv-tools/test/fuzz/transformation_copy_object_test.cpp +++ b/3rdparty/spirv-tools/test/fuzz/transformation_copy_object_test.cpp @@ -14,6 +14,7 @@ #include "source/fuzz/transformation_copy_object.h" #include "source/fuzz/data_descriptor.h" +#include "source/fuzz/instruction_descriptor.h" #include "test/fuzz/fuzz_test_util.h" namespace spvtools { @@ -49,7 +50,8 @@ TEST(TransformationCopyObjectTest, CopyBooleanConstants) { ASSERT_EQ(0, fact_manager.GetIdsForWhichSynonymsAreKnown().size()); - TransformationCopyObject copy_true(7, 5, 1, 100); + TransformationCopyObject copy_true( + 7, MakeInstructionDescriptor(5, SpvOpReturn, 0), 100); ASSERT_TRUE(copy_true.IsApplicable(context.get(), fact_manager)); copy_true.Apply(context.get(), &fact_manager); @@ -63,7 +65,8 @@ TEST(TransformationCopyObjectTest, CopyBooleanConstants) { ASSERT_TRUE(DataDescriptorEquals()(&descriptor_100, &fact_manager.GetSynonymsForId(7)[0])); - TransformationCopyObject copy_false(8, 100, 1, 101); + TransformationCopyObject copy_false( + 8, MakeInstructionDescriptor(100, SpvOpReturn, 0), 101); ASSERT_TRUE(copy_false.IsApplicable(context.get(), fact_manager)); copy_false.Apply(context.get(), &fact_manager); ASSERT_EQ(2, ids_for_which_synonyms_are_known.size()); @@ -74,7 +77,8 @@ TEST(TransformationCopyObjectTest, CopyBooleanConstants) { ASSERT_TRUE(DataDescriptorEquals()(&descriptor_101, &fact_manager.GetSynonymsForId(8)[0])); - TransformationCopyObject copy_false_again(101, 5, 3, 102); + TransformationCopyObject copy_false_again( + 101, MakeInstructionDescriptor(5, SpvOpReturn, 0), 102); ASSERT_TRUE(copy_false_again.IsApplicable(context.get(), fact_manager)); copy_false_again.Apply(context.get(), &fact_manager); ASSERT_EQ(3, ids_for_which_synonyms_are_known.size()); @@ -85,7 +89,8 @@ TEST(TransformationCopyObjectTest, CopyBooleanConstants) { ASSERT_TRUE(DataDescriptorEquals()(&descriptor_102, &fact_manager.GetSynonymsForId(101)[0])); - TransformationCopyObject copy_true_again(7, 102, 1, 103); + TransformationCopyObject copy_true_again( + 7, MakeInstructionDescriptor(102, SpvOpReturn, 0), 103); ASSERT_TRUE(copy_true_again.IsApplicable(context.get(), fact_manager)); copy_true_again.Apply(context.get(), &fact_manager); // This does re-uses an id for which synonyms are already known, so the count @@ -318,90 +323,113 @@ TEST(TransformationCopyObjectTest, CheckIllegalCases) { FactManager fact_manager; // Inapplicable because %18 is decorated. - ASSERT_FALSE(TransformationCopyObject(18, 21, 0, 200) + ASSERT_FALSE(TransformationCopyObject( + 18, MakeInstructionDescriptor(21, SpvOpAccessChain, 0), 200) .IsApplicable(context.get(), fact_manager)); // Inapplicable because %77 is decorated. - ASSERT_FALSE(TransformationCopyObject(17, 17, 1, 200) + ASSERT_FALSE(TransformationCopyObject( + 77, MakeInstructionDescriptor(77, SpvOpBranch, 0), 200) .IsApplicable(context.get(), fact_manager)); // Inapplicable because %80 is decorated. - ASSERT_FALSE(TransformationCopyObject(80, 77, 0, 200) + ASSERT_FALSE(TransformationCopyObject( + 80, MakeInstructionDescriptor(77, SpvOpIAdd, 0), 200) .IsApplicable(context.get(), fact_manager)); // Inapplicable because %84 is not available at the requested point - ASSERT_FALSE(TransformationCopyObject(84, 32, 1, 200) - .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationCopyObject( + 84, MakeInstructionDescriptor(32, SpvOpCompositeExtract, 0), 200) + .IsApplicable(context.get(), fact_manager)); // Fine because %84 is available at the requested point - ASSERT_TRUE(TransformationCopyObject(84, 32, 2, 200) - .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationCopyObject( + 84, MakeInstructionDescriptor(32, SpvOpCompositeConstruct, 0), 200) + .IsApplicable(context.get(), fact_manager)); // Inapplicable because id %9 is already in use - ASSERT_FALSE(TransformationCopyObject(84, 32, 2, 9) - .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationCopyObject( + 84, MakeInstructionDescriptor(32, SpvOpCompositeConstruct, 0), 9) + .IsApplicable(context.get(), fact_manager)); - // Inapplicable because the requested point is not in a block - ASSERT_FALSE(TransformationCopyObject(84, 86, 3, 200) + // Inapplicable because the requested point does not exist + ASSERT_FALSE(TransformationCopyObject( + 84, MakeInstructionDescriptor(86, SpvOpReturn, 2), 200) .IsApplicable(context.get(), fact_manager)); // Inapplicable because %9 is not in a function - ASSERT_FALSE(TransformationCopyObject(9, 9, 1, 200) - .IsApplicable(context.get(), fact_manager)); - - // Inapplicable because %9 is not in a function - ASSERT_FALSE(TransformationCopyObject(9, 9, 1, 200) + ASSERT_FALSE(TransformationCopyObject( + 9, MakeInstructionDescriptor(9, SpvOpTypeInt, 0), 200) .IsApplicable(context.get(), fact_manager)); // Inapplicable because the insert point is right before, or inside, a chunk // of OpPhis - ASSERT_FALSE(TransformationCopyObject(9, 30, 1, 200) + ASSERT_FALSE(TransformationCopyObject( + 9, MakeInstructionDescriptor(30, SpvOpPhi, 0), 200) .IsApplicable(context.get(), fact_manager)); - ASSERT_FALSE(TransformationCopyObject(9, 99, 1, 200) + ASSERT_FALSE(TransformationCopyObject( + 9, MakeInstructionDescriptor(99, SpvOpPhi, 1), 200) .IsApplicable(context.get(), fact_manager)); // OK, because the insert point is just after a chunk of OpPhis. - ASSERT_TRUE(TransformationCopyObject(9, 96, 1, 200) + ASSERT_TRUE(TransformationCopyObject( + 9, MakeInstructionDescriptor(96, SpvOpAccessChain, 0), 200) .IsApplicable(context.get(), fact_manager)); // Inapplicable because the insert point is right after an OpSelectionMerge - ASSERT_FALSE(TransformationCopyObject(9, 58, 2, 200) - .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationCopyObject( + 9, MakeInstructionDescriptor(58, SpvOpBranchConditional, 0), 200) + .IsApplicable(context.get(), fact_manager)); // OK, because the insert point is right before the OpSelectionMerge - ASSERT_TRUE(TransformationCopyObject(9, 58, 1, 200) + ASSERT_TRUE(TransformationCopyObject( + 9, MakeInstructionDescriptor(58, SpvOpSelectionMerge, 0), 200) .IsApplicable(context.get(), fact_manager)); // Inapplicable because the insert point is right after an OpSelectionMerge - ASSERT_FALSE(TransformationCopyObject(9, 43, 2, 200) + ASSERT_FALSE(TransformationCopyObject( + 9, MakeInstructionDescriptor(43, SpvOpSwitch, 0), 200) .IsApplicable(context.get(), fact_manager)); // OK, because the insert point is right before the OpSelectionMerge - ASSERT_TRUE(TransformationCopyObject(9, 43, 1, 200) + ASSERT_TRUE(TransformationCopyObject( + 9, MakeInstructionDescriptor(43, SpvOpSelectionMerge, 0), 200) .IsApplicable(context.get(), fact_manager)); // Inapplicable because the insert point is right after an OpLoopMerge - ASSERT_FALSE(TransformationCopyObject(9, 40, 2, 200) - .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationCopyObject( + 9, MakeInstructionDescriptor(40, SpvOpBranchConditional, 0), 200) + .IsApplicable(context.get(), fact_manager)); // OK, because the insert point is right before the OpLoopMerge - ASSERT_TRUE(TransformationCopyObject(9, 40, 1, 200) + ASSERT_TRUE(TransformationCopyObject( + 9, MakeInstructionDescriptor(40, SpvOpLoopMerge, 0), 200) .IsApplicable(context.get(), fact_manager)); // Inapplicable because id %300 does not exist - ASSERT_FALSE(TransformationCopyObject(300, 40, 1, 200) + ASSERT_FALSE(TransformationCopyObject( + 300, MakeInstructionDescriptor(40, SpvOpLoopMerge, 0), 200) .IsApplicable(context.get(), fact_manager)); // Inapplicable because the following instruction is OpVariable - ASSERT_FALSE(TransformationCopyObject(9, 180, 0, 200) + ASSERT_FALSE(TransformationCopyObject( + 9, MakeInstructionDescriptor(180, SpvOpVariable, 0), 200) .IsApplicable(context.get(), fact_manager)); - ASSERT_FALSE(TransformationCopyObject(9, 181, 0, 200) + ASSERT_FALSE(TransformationCopyObject( + 9, MakeInstructionDescriptor(181, SpvOpVariable, 0), 200) .IsApplicable(context.get(), fact_manager)); - ASSERT_FALSE(TransformationCopyObject(9, 182, 0, 200) + ASSERT_FALSE(TransformationCopyObject( + 9, MakeInstructionDescriptor(182, SpvOpVariable, 0), 200) .IsApplicable(context.get(), fact_manager)); // OK, because this is just past the group of OpVariable instructions. - ASSERT_TRUE(TransformationCopyObject(9, 182, 1, 200) + ASSERT_TRUE(TransformationCopyObject( + 9, MakeInstructionDescriptor(182, SpvOpAccessChain, 0), 200) .IsApplicable(context.get(), fact_manager)); } @@ -470,13 +498,20 @@ TEST(TransformationCopyObjectTest, MiscellaneousCopies) { FactManager fact_manager; std::vector transformations = { - TransformationCopyObject(19, 22, 1, 100), - TransformationCopyObject(22, 22, 1, 101), - TransformationCopyObject(12, 22, 1, 102), - TransformationCopyObject(11, 22, 1, 103), - TransformationCopyObject(16, 22, 1, 104), - TransformationCopyObject(8, 22, 1, 105), - TransformationCopyObject(17, 22, 1, 106)}; + TransformationCopyObject(19, MakeInstructionDescriptor(22, SpvOpStore, 0), + 100), + TransformationCopyObject( + 22, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 101), + TransformationCopyObject( + 12, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 102), + TransformationCopyObject( + 11, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 103), + TransformationCopyObject( + 16, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 104), + TransformationCopyObject( + 8, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 105), + TransformationCopyObject( + 17, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 106)}; for (auto& transformation : transformations) { ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); diff --git a/3rdparty/spirv-tools/test/fuzz/transformation_split_block_test.cpp b/3rdparty/spirv-tools/test/fuzz/transformation_split_block_test.cpp index dc6d4d037..d162e0715 100644 --- a/3rdparty/spirv-tools/test/fuzz/transformation_split_block_test.cpp +++ b/3rdparty/spirv-tools/test/fuzz/transformation_split_block_test.cpp @@ -13,6 +13,7 @@ // limitations under the License. #include "source/fuzz/transformation_split_block.h" +#include "source/fuzz/instruction_descriptor.h" #include "test/fuzz/fuzz_test_util.h" namespace spvtools { @@ -90,44 +91,55 @@ TEST(TransformationSplitBlockTest, NotApplicable) { FactManager fact_manager; // No split before OpVariable - ASSERT_FALSE(TransformationSplitBlock(8, 0, 100).IsApplicable(context.get(), - fact_manager)); - ASSERT_FALSE(TransformationSplitBlock(8, 1, 100).IsApplicable(context.get(), - fact_manager)); + ASSERT_FALSE(TransformationSplitBlock( + MakeInstructionDescriptor(8, SpvOpVariable, 0), 100) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSplitBlock( + MakeInstructionDescriptor(8, SpvOpVariable, 1), 100) + .IsApplicable(context.get(), fact_manager)); // No split before OpLabel - ASSERT_FALSE(TransformationSplitBlock(14, 0, 100) + ASSERT_FALSE(TransformationSplitBlock( + MakeInstructionDescriptor(14, SpvOpLabel, 0), 100) .IsApplicable(context.get(), fact_manager)); // No split if base instruction is outside a function - ASSERT_FALSE(TransformationSplitBlock(1, 0, 100).IsApplicable(context.get(), - fact_manager)); - ASSERT_FALSE(TransformationSplitBlock(1, 4, 100).IsApplicable(context.get(), - fact_manager)); - ASSERT_FALSE(TransformationSplitBlock(1, 35, 100) + ASSERT_FALSE( + TransformationSplitBlock(MakeInstructionDescriptor(1, SpvOpLabel, 0), 100) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSplitBlock( + MakeInstructionDescriptor(1, SpvOpExecutionMode, 0), 100) .IsApplicable(context.get(), fact_manager)); // No split if block is loop header - ASSERT_FALSE(TransformationSplitBlock(27, 0, 100) - .IsApplicable(context.get(), fact_manager)); - ASSERT_FALSE(TransformationSplitBlock(27, 1, 100) - .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 0), 100) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 1), 100) + .IsApplicable(context.get(), fact_manager)); // No split if base instruction does not exist - ASSERT_FALSE(TransformationSplitBlock(88, 0, 100) - .IsApplicable(context.get(), fact_manager)); - ASSERT_FALSE(TransformationSplitBlock(88, 22, 100) + ASSERT_FALSE( + TransformationSplitBlock(MakeInstructionDescriptor(88, SpvOpIAdd, 0), 100) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSplitBlock( + MakeInstructionDescriptor(88, SpvOpIMul, 22), 100) .IsApplicable(context.get(), fact_manager)); - // No split if offset is too large (goes into another block) - ASSERT_FALSE(TransformationSplitBlock(18, 3, 100) - .IsApplicable(context.get(), fact_manager)); + // No split if too many instructions with the desired opcode are skipped + ASSERT_FALSE( + TransformationSplitBlock( + MakeInstructionDescriptor(18, SpvOpBranchConditional, 1), 100) + .IsApplicable(context.get(), fact_manager)); // No split if id in use - ASSERT_FALSE(TransformationSplitBlock(18, 0, 27).IsApplicable(context.get(), - fact_manager)); - ASSERT_FALSE(TransformationSplitBlock(18, 0, 14).IsApplicable(context.get(), - fact_manager)); + ASSERT_FALSE(TransformationSplitBlock( + MakeInstructionDescriptor(18, SpvOpSLessThan, 0), 27) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSplitBlock( + MakeInstructionDescriptor(18, SpvOpSLessThan, 0), 14) + .IsApplicable(context.get(), fact_manager)); } TEST(TransformationSplitBlockTest, SplitBlockSeveralTimes) { @@ -188,7 +200,8 @@ TEST(TransformationSplitBlockTest, SplitBlockSeveralTimes) { FactManager fact_manager; - auto split_1 = TransformationSplitBlock(5, 3, 100); + auto split_1 = TransformationSplitBlock( + MakeInstructionDescriptor(5, SpvOpStore, 0), 100); ASSERT_TRUE(split_1.IsApplicable(context.get(), fact_manager)); split_1.Apply(context.get(), &fact_manager); ASSERT_TRUE(IsValid(env, context.get())); @@ -235,7 +248,8 @@ TEST(TransformationSplitBlockTest, SplitBlockSeveralTimes) { )"; ASSERT_TRUE(IsEqual(env, after_split_1, context.get())); - auto split_2 = TransformationSplitBlock(11, 1, 101); + auto split_2 = TransformationSplitBlock( + MakeInstructionDescriptor(11, SpvOpStore, 0), 101); ASSERT_TRUE(split_2.IsApplicable(context.get(), fact_manager)); split_2.Apply(context.get(), &fact_manager); ASSERT_TRUE(IsValid(env, context.get())); @@ -284,7 +298,8 @@ TEST(TransformationSplitBlockTest, SplitBlockSeveralTimes) { )"; ASSERT_TRUE(IsEqual(env, after_split_2, context.get())); - auto split_3 = TransformationSplitBlock(14, 0, 102); + auto split_3 = TransformationSplitBlock( + MakeInstructionDescriptor(14, SpvOpLoad, 0), 102); ASSERT_TRUE(split_3.IsApplicable(context.get(), fact_manager)); split_3.Apply(context.get(), &fact_manager); ASSERT_TRUE(IsValid(env, context.get())); @@ -399,12 +414,17 @@ TEST(TransformationSplitBlockTest, SplitBlockBeforeSelectBranch) { FactManager fact_manager; // Illegal to split between the merge and the conditional branch. - ASSERT_FALSE(TransformationSplitBlock(14, 2, 100) - .IsApplicable(context.get(), fact_manager)); - ASSERT_FALSE(TransformationSplitBlock(12, 3, 100) - .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSplitBlock( + MakeInstructionDescriptor(14, SpvOpBranchConditional, 0), 100) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSplitBlock( + MakeInstructionDescriptor(12, SpvOpBranchConditional, 0), 100) + .IsApplicable(context.get(), fact_manager)); - auto split = TransformationSplitBlock(14, 1, 100); + auto split = TransformationSplitBlock( + MakeInstructionDescriptor(14, SpvOpSelectionMerge, 0), 100); ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager)); split.Apply(context.get(), &fact_manager); ASSERT_TRUE(IsValid(env, context.get())); @@ -523,12 +543,15 @@ TEST(TransformationSplitBlockTest, SplitBlockBeforeSwitchBranch) { FactManager fact_manager; // Illegal to split between the merge and the conditional branch. - ASSERT_FALSE(TransformationSplitBlock(9, 2, 100).IsApplicable(context.get(), - fact_manager)); - ASSERT_FALSE(TransformationSplitBlock(15, 3, 100) + ASSERT_FALSE(TransformationSplitBlock( + MakeInstructionDescriptor(9, SpvOpSwitch, 0), 100) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSplitBlock( + MakeInstructionDescriptor(15, SpvOpSwitch, 0), 100) .IsApplicable(context.get(), fact_manager)); - auto split = TransformationSplitBlock(9, 1, 100); + auto split = TransformationSplitBlock( + MakeInstructionDescriptor(9, SpvOpSelectionMerge, 0), 100); ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager)); split.Apply(context.get(), &fact_manager); ASSERT_TRUE(IsValid(env, context.get())); @@ -654,12 +677,15 @@ TEST(TransformationSplitBlockTest, NoSplitDuringOpPhis) { // We cannot split before OpPhi instructions, since the number of incoming // blocks may not appropriately match after splitting. - ASSERT_FALSE(TransformationSplitBlock(26, 0, 100) - .IsApplicable(context.get(), fact_manager)); - ASSERT_FALSE(TransformationSplitBlock(27, 0, 100) - .IsApplicable(context.get(), fact_manager)); - ASSERT_FALSE(TransformationSplitBlock(27, 1, 100) - .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSplitBlock(MakeInstructionDescriptor(26, SpvOpPhi, 0), 100) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 0), 100) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 1), 100) + .IsApplicable(context.get(), fact_manager)); } TEST(TransformationSplitBlockTest, SplitOpPhiWithSinglePredecessor) { @@ -701,9 +727,13 @@ TEST(TransformationSplitBlockTest, SplitOpPhiWithSinglePredecessor) { FactManager fact_manager; - ASSERT_TRUE(TransformationSplitBlock(21, 0, 100) - .IsApplicable(context.get(), fact_manager)); - auto split = TransformationSplitBlock(20, 1, 100); + ASSERT_TRUE( + TransformationSplitBlock(MakeInstructionDescriptor(21, SpvOpPhi, 0), 100) + .IsApplicable(context.get(), fact_manager)); + // An equivalent transformation to the above, just described with respect to a + // different base instruction. + auto split = + TransformationSplitBlock(MakeInstructionDescriptor(20, SpvOpPhi, 0), 100); ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager)); split.Apply(context.get(), &fact_manager); ASSERT_TRUE(IsValid(env, context.get())); diff --git a/3rdparty/spirv-tools/test/fuzzers/BUILD.gn b/3rdparty/spirv-tools/test/fuzzers/BUILD.gn index c565e113b..be1258a45 100644 --- a/3rdparty/spirv-tools/test/fuzzers/BUILD.gn +++ b/3rdparty/spirv-tools/test/fuzzers/BUILD.gn @@ -33,7 +33,9 @@ if (!build_with_chromium || use_fuzzing_engine) { testonly = true deps = [ + ":spvtools_as_fuzzer", ":spvtools_binary_parser_fuzzer", + ":spvtools_dis_fuzzer", ":spvtools_opt_legalization_fuzzer", ":spvtools_opt_performance_fuzzer", ":spvtools_opt_size_fuzzer", @@ -66,12 +68,24 @@ template("spvtools_fuzzer") { } } +spvtools_fuzzer("spvtools_as_fuzzer_src") { + sources = [ + "spvtools_as_fuzzer.cpp", + ] +} + spvtools_fuzzer("spvtools_binary_parser_fuzzer_src") { sources = [ "spvtools_binary_parser_fuzzer.cpp", ] } +spvtools_fuzzer("spvtools_dis_fuzzer_src") { + sources = [ + "spvtools_dis_fuzzer.cpp", + ] +} + spvtools_fuzzer("spvtools_opt_performance_fuzzer_src") { sources = [ "spvtools_opt_performance_fuzzer.cpp", @@ -116,6 +130,15 @@ spvtools_fuzzer("spvtools_val_webgpu_fuzzer_src") { } if (!build_with_chromium || use_fuzzing_engine) { + fuzzer_test("spvtools_as_fuzzer") { + sources = [] + deps = [ + ":spvtools_as_fuzzer_src", + ] + # Intentionally doesn't use the seed corpus, because it consumes + # part of the input as not part of the file. + } + fuzzer_test("spvtools_binary_parser_fuzzer") { sources = [] deps = [ @@ -125,6 +148,15 @@ if (!build_with_chromium || use_fuzzing_engine) { # part of the input as not part of the file. } + fuzzer_test("spvtools_dis_fuzzer") { + sources = [] + deps = [ + ":spvtools_dis_fuzzer_src", + ] + # Intentionally doesn't use the seed corpus, because it consumes + # part of the input as not part of the file. + } + fuzzer_test("spvtools_opt_performance_fuzzer") { sources = [] deps = [ diff --git a/3rdparty/spirv-tools/test/fuzzers/spvtools_as_fuzzer.cpp b/3rdparty/spirv-tools/test/fuzzers/spvtools_as_fuzzer.cpp new file mode 100644 index 000000000..1b1de0082 --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzzers/spvtools_as_fuzzer.cpp @@ -0,0 +1,70 @@ +// Copyright (c) 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include // memcpy +#include + +#include "source/spirv_target_env.h" +#include "spirv-tools/libspirv.hpp" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (size < sizeof(spv_target_env) + 1) return 0; + + const spv_context context = + spvContextCreate(*reinterpret_cast(data)); + if (context == nullptr) return 0; + + data += sizeof(spv_target_env); + size -= sizeof(spv_target_env); + + std::vector input; + + std::vector input_str; + size_t char_count = input.size() * sizeof(uint32_t) / sizeof(char); + input_str.resize(char_count); + memcpy(input_str.data(), input.data(), input.size() * sizeof(uint32_t)); + + spv_binary binary; + spv_diagnostic diagnostic = nullptr; + spvTextToBinaryWithOptions(context, input_str.data(), input_str.size(), + SPV_TEXT_TO_BINARY_OPTION_NONE, &binary, + &diagnostic); + if (diagnostic) { + spvDiagnosticPrint(diagnostic); + spvDiagnosticDestroy(diagnostic); + diagnostic = nullptr; + } + + if (binary) { + spvBinaryDestroy(binary); + binary = nullptr; + } + + spvTextToBinaryWithOptions(context, input_str.data(), input_str.size(), + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS, + &binary, &diagnostic); + if (diagnostic) { + spvDiagnosticPrint(diagnostic); + spvDiagnosticDestroy(diagnostic); + diagnostic = nullptr; + } + + if (binary) { + spvBinaryDestroy(binary); + binary = nullptr; + } + + return 0; +} diff --git a/3rdparty/spirv-tools/test/fuzzers/spvtools_dis_fuzzer.cpp b/3rdparty/spirv-tools/test/fuzzers/spvtools_dis_fuzzer.cpp new file mode 100644 index 000000000..07876aef6 --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzzers/spvtools_dis_fuzzer.cpp @@ -0,0 +1,64 @@ +// Copyright (c) 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include // memcpy +#include + +#include "source/spirv_target_env.h" +#include "spirv-tools/libspirv.hpp" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (size < sizeof(spv_target_env) + 1) return 0; + + const spv_context context = + spvContextCreate(*reinterpret_cast(data)); + if (context == nullptr) return 0; + + data += sizeof(spv_target_env); + size -= sizeof(spv_target_env); + + std::vector input; + input.resize(size >> 2); + size_t count = 0; + for (size_t i = 0; (i + 3) < size; i += 4) { + input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) | + (data[i + 3]) << 24; + } + + std::vector input_str; + size_t char_count = input.size() * sizeof(uint32_t) / sizeof(char); + input_str.resize(char_count); + memcpy(input_str.data(), input.data(), input.size() * sizeof(uint32_t)); + + spv_text text = nullptr; + spv_diagnostic diagnostic = nullptr; + + for (uint32_t options = SPV_BINARY_TO_TEXT_OPTION_NONE; + options < + (SPV_BINARY_TO_TEXT_OPTION_PRINT | SPV_BINARY_TO_TEXT_OPTION_COLOR | + SPV_BINARY_TO_TEXT_OPTION_INDENT | + SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET | + SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | + SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); + options++) { + spvBinaryToText(context, input.data(), input.size(), options, &text, + &diagnostic); + if (diagnostic) spvDiagnosticDestroy(diagnostic); + if (text) spvTextDestroy(text); + } + + spvContextDestroy(context); + return 0; +} diff --git a/3rdparty/spirv-tools/test/opt/fold_spec_const_op_composite_test.cpp b/3rdparty/spirv-tools/test/opt/fold_spec_const_op_composite_test.cpp index c96dc8c5a..7eddf7e99 100644 --- a/3rdparty/spirv-tools/test/opt/fold_spec_const_op_composite_test.cpp +++ b/3rdparty/spirv-tools/test/opt/fold_spec_const_op_composite_test.cpp @@ -112,8 +112,12 @@ std::vector CommonTypesAndConstants() { // clang-format off // scalar types "%bool = OpTypeBool", + "%ushort = OpTypeInt 16 0", + "%short = OpTypeInt 16 1", "%uint = OpTypeInt 32 0", "%int = OpTypeInt 32 1", + "%ulong = OpTypeInt 64 0", + "%long = OpTypeInt 64 1", "%float = OpTypeFloat 32", "%double = OpTypeFloat 64", // vector types @@ -122,6 +126,8 @@ std::vector CommonTypesAndConstants() { "%v2int = OpTypeVector %int 2", "%v3int = OpTypeVector %int 3", "%v4int = OpTypeVector %int 4", + "%v2long = OpTypeVector %long 2", + "%v2ulong = OpTypeVector %ulong 2", "%v2float = OpTypeVector %float 2", "%v2double = OpTypeVector %double 2", // variable pointer types @@ -145,6 +151,8 @@ std::vector CommonTypesAndConstants() { "%bool_null = OpConstantNull %bool", "%signed_zero = OpConstant %int 0", "%unsigned_zero = OpConstant %uint 0", + "%long_zero = OpConstant %long 0", + "%ulong_zero = OpConstant %ulong 0", "%signed_one = OpConstant %int 1", "%unsigned_one = OpConstant %uint 1", "%signed_two = OpConstant %int 2", @@ -153,6 +161,7 @@ std::vector CommonTypesAndConstants() { "%unsigned_three = OpConstant %uint 3", "%signed_null = OpConstantNull %int", "%unsigned_null = OpConstantNull %uint", + "%signed_minus_one = OpConstant %int -1", // vector constants: "%bool_true_vec = OpConstantComposite %v2bool %bool_true %bool_true", "%bool_false_vec = OpConstantComposite %v2bool %bool_false %bool_false", @@ -167,6 +176,7 @@ std::vector CommonTypesAndConstants() { "%unsigned_three_vec = OpConstantComposite %v2uint %unsigned_three %unsigned_three", "%signed_null_vec = OpConstantNull %v2int", "%unsigned_null_vec = OpConstantNull %v2uint", + "%signed_minus_one_vec = OpConstantComposite %v2int %signed_minus_one %signed_minus_one", "%v4int_0_1_2_3 = OpConstantComposite %v4int %signed_zero %signed_one %signed_two %signed_three", // clang-format on }; @@ -345,9 +355,9 @@ INSTANTIATE_TEST_SUITE_P( // Tests for operations that resulting in different types. INSTANTIATE_TEST_SUITE_P( Cast, FoldSpecConstantOpAndCompositePassTest, - ::testing::ValuesIn( - std::vector({ - // clang-format off + ::testing::ValuesIn(std::vector< + FoldSpecConstantOpAndCompositePassTestCase>({ + // clang-format off // int -> bool scalar { // original @@ -575,8 +585,108 @@ INSTANTIATE_TEST_SUITE_P( "%spec_uint_from_null = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero", }, }, - // clang-format on - }))); + + // UConvert scalar + { + // original + { + "%spec_uint_zero = OpSpecConstantOp %uint UConvert %bool_false", + "%spec_uint_one = OpSpecConstantOp %uint UConvert %bool_true", + "%spec_ulong_zero = OpSpecConstantOp %ulong UConvert %unsigned_zero", + "%spec_ulong_one = OpSpecConstantOp %ulong UConvert %unsigned_one", + "%spec_short_zero = OpSpecConstantOp %ushort UConvert %unsigned_zero", + "%spec_short_one = OpSpecConstantOp %ushort UConvert %unsigned_one", + "%uint_max = OpConstant %uint 4294967295", + "%spec_ushort_max = OpSpecConstantOp %ushort UConvert %uint_max", + "%uint_0xDDDDDDDD = OpConstant %uint 3722304989", + "%spec_ushort_0xDDDD = OpSpecConstantOp %ushort UConvert %uint_0xDDDDDDDD", + }, + // expected + { + "%spec_uint_zero = OpConstant %uint 0", + "%spec_uint_one = OpConstant %uint 1", + "%spec_ulong_zero = OpConstant %ulong 0", + "%spec_ulong_one = OpConstant %ulong 1", + "%spec_short_zero = OpConstant %ushort 0", + "%spec_short_one = OpConstant %ushort 1", + "%uint_max = OpConstant %uint 4294967295", + "%spec_ushort_max = OpConstant %ushort 65535", + "%uint_0xDDDDDDDD = OpConstant %uint 3722304989", + "%spec_ushort_0xDDDD = OpConstant %ushort 56797", + }, + }, + + // SConvert scalar + { + // original + { + "%spec_long_zero = OpSpecConstantOp %long SConvert %signed_zero", + "%spec_long_one = OpSpecConstantOp %long SConvert %signed_one", + "%spec_long_minus_one = OpSpecConstantOp %long SConvert %signed_minus_one", + "%spec_short_minus_one_trunc = OpSpecConstantOp %short SConvert %signed_minus_one", + "%int_2_to_17_minus_one = OpConstant %int 131071", + "%spec_short_minus_one_trunc2 = OpSpecConstantOp %short SConvert %int_2_to_17_minus_one", + }, + // expected + { + "%spec_long_zero = OpConstant %long 0", + "%spec_long_one = OpConstant %long 1", + "%spec_long_minus_one = OpConstant %long -1", + "%spec_short_minus_one_trunc = OpConstant %short -1", + "%int_2_to_17_minus_one = OpConstant %int 131071", + "%spec_short_minus_one_trunc2 = OpConstant %short -1", + }, + }, + + // UConvert vector + { + // original + { + "%spec_v2uint_zero = OpSpecConstantOp %v2uint UConvert %bool_false_vec", + "%spec_v2uint_one = OpSpecConstantOp %v2uint UConvert %bool_true_vec", + "%spec_v2ulong_zero = OpSpecConstantOp %v2ulong UConvert %unsigned_zero_vec", + "%spec_v2ulong_one = OpSpecConstantOp %v2ulong UConvert %unsigned_one_vec", + }, + // expected + { + "%uint_0 = OpConstant %uint 0", + "%uint_0_0 = OpConstant %uint 0", + "%spec_v2uint_zero = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero", + "%uint_1 = OpConstant %uint 1", + "%uint_1_0 = OpConstant %uint 1", + "%spec_v2uint_one = OpConstantComposite %v2uint %unsigned_one %unsigned_one", + "%ulong_0 = OpConstant %ulong 0", + "%ulong_0_0 = OpConstant %ulong 0", + "%spec_v2ulong_zero = OpConstantComposite %v2ulong %ulong_zero %ulong_zero", + "%ulong_1 = OpConstant %ulong 1", + "%ulong_1_0 = OpConstant %ulong 1", + "%spec_v2ulong_one = OpConstantComposite %v2ulong %ulong_1 %ulong_1", + }, + }, + + // SConvert vector + { + // original + { + "%spec_v2long_zero = OpSpecConstantOp %v2long SConvert %signed_zero_vec", + "%spec_v2long_one = OpSpecConstantOp %v2long SConvert %signed_one_vec", + "%spec_v2long_minus_one = OpSpecConstantOp %v2long SConvert %signed_minus_one_vec", + }, + // expected + { + "%long_0 = OpConstant %long 0", + "%long_0_0 = OpConstant %long 0", + "%spec_v2long_zero = OpConstantComposite %v2long %long_zero %long_zero", + "%long_1 = OpConstant %long 1", + "%long_1_0 = OpConstant %long 1", + "%spec_v2long_one = OpConstantComposite %v2long %long_1 %long_1", + "%long_n1 = OpConstant %long -1", + "%long_n1_0 = OpConstant %long -1", + "%spec_v2long_minus_one = OpConstantComposite %v2long %long_n1 %long_n1", + }, + }, + // clang-format on + }))); // Tests about boolean scalar logical operations and comparison operations with // scalar int/uint type. @@ -851,7 +961,7 @@ INSTANTIATE_TEST_SUITE_P( { "%int_n1 = OpConstant %int -1", "%int_n1_0 = OpConstant %int -1", - "%v2int_minus_1 = OpConstantComposite %v2int %int_n1 %int_n1", + "%v2int_minus_1 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one", "%int_n2 = OpConstant %int -2", "%int_n2_0 = OpConstant %int -2", "%v2int_minus_2 = OpConstantComposite %v2int %int_n2 %int_n2", @@ -956,13 +1066,13 @@ INSTANTIATE_TEST_SUITE_P( "%7_srem_3 = OpConstantComposite %v2int %signed_one %signed_one", "%int_n1 = OpConstant %int -1", "%int_n1_0 = OpConstant %int -1", - "%minus_7_srem_3 = OpConstantComposite %v2int %int_n1 %int_n1", + "%minus_7_srem_3 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one", "%int_1_1 = OpConstant %int 1", "%int_1_2 = OpConstant %int 1", "%7_srem_minus_3 = OpConstantComposite %v2int %signed_one %signed_one", "%int_n1_1 = OpConstant %int -1", "%int_n1_2 = OpConstant %int -1", - "%minus_7_srem_minus_3 = OpConstantComposite %v2int %int_n1 %int_n1", + "%minus_7_srem_minus_3 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one", // smod "%int_1_3 = OpConstant %int 1", "%int_1_4 = OpConstant %int 1", @@ -975,7 +1085,7 @@ INSTANTIATE_TEST_SUITE_P( "%7_smod_minus_3 = OpConstantComposite %v2int %int_n2 %int_n2", "%int_n1_3 = OpConstant %int -1", "%int_n1_4 = OpConstant %int -1", - "%minus_7_smod_minus_3 = OpConstantComposite %v2int %int_n1 %int_n1", + "%minus_7_smod_minus_3 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one", // umod "%uint_1 = OpConstant %uint 1", "%uint_1_0 = OpConstant %uint 1", @@ -1018,7 +1128,7 @@ INSTANTIATE_TEST_SUITE_P( "%unsigned_right_shift_logical = OpConstantComposite %v2uint %unsigned_one %unsigned_one", "%int_n1 = OpConstant %int -1", "%int_n1_0 = OpConstant %int -1", - "%signed_right_shift_arithmetic = OpConstantComposite %v2int %int_n1 %int_n1", + "%signed_right_shift_arithmetic = OpConstantComposite %v2int %signed_minus_one %signed_minus_one", }, }, // Skip folding if any vector operands or components of the operands diff --git a/3rdparty/spirv-tools/test/opt/fold_test.cpp b/3rdparty/spirv-tools/test/opt/fold_test.cpp index 5c2adec90..cb81f1c4a 100644 --- a/3rdparty/spirv-tools/test/opt/fold_test.cpp +++ b/3rdparty/spirv-tools/test/opt/fold_test.cpp @@ -3333,16 +3333,7 @@ INSTANTIATE_TEST_SUITE_P(CompositeExtractFoldingTest, GeneralInstructionFoldingT "%3 = OpCompositeExtract %float %2 4\n" + "OpReturn\n" + "OpFunctionEnd", - 3, 0), - // Test case 14: Fold OpCompositeExtract with no indexes. - InstructionFoldingCase( - Header() + "%main = OpFunction %void None %void_func\n" + - "%main_lab = OpLabel\n" + - "%2 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1\n" + - "%3 = OpCompositeExtract %v4float %2\n" + - "OpReturn\n" + - "OpFunctionEnd", - 3, 2) + 3, 0) )); INSTANTIATE_TEST_SUITE_P(CompositeConstructFoldingTest, GeneralInstructionFoldingTest, diff --git a/3rdparty/spirv-tools/test/opt/optimizer_test.cpp b/3rdparty/spirv-tools/test/opt/optimizer_test.cpp index 5e9ea950c..5c0707d73 100644 --- a/3rdparty/spirv-tools/test/opt/optimizer_test.cpp +++ b/3rdparty/spirv-tools/test/opt/optimizer_test.cpp @@ -744,6 +744,54 @@ INSTANTIATE_TEST_SUITE_P( // pass "compact-ids"}})); +TEST(Optimizer, RemoveNop) { + // Test that OpNops are removed even if no optimizations are run. + const std::string before = R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%2 = OpTypeFunction %void +%3 = OpFunction %void None %2 +%4 = OpLabel +OpNop +OpReturn +OpFunctionEnd +)"; + + const std::string after = R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%2 = OpTypeFunction %void +%3 = OpFunction %void None %2 +%4 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::vector binary; + { + SpirvTools tools(SPV_ENV_VULKAN_1_1); + tools.Assemble(before, &binary); + } + + Optimizer opt(SPV_ENV_VULKAN_1_1); + + std::vector optimized; + class ValidatorOptions validator_options; + ASSERT_TRUE(opt.Run(binary.data(), binary.size(), &optimized, + validator_options, true)) + << before << "\n"; + std::string disassembly; + { + SpirvTools tools(SPV_ENV_WEBGPU_0); + tools.Disassemble(optimized.data(), optimized.size(), &disassembly); + } + + EXPECT_EQ(after, disassembly) + << "Was expecting the OpNop to have been removed."; +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/opt/reduce_load_size_test.cpp b/3rdparty/spirv-tools/test/opt/reduce_load_size_test.cpp index 7b850e317..50dc5017c 100644 --- a/3rdparty/spirv-tools/test/opt/reduce_load_size_test.cpp +++ b/3rdparty/spirv-tools/test/opt/reduce_load_size_test.cpp @@ -321,34 +321,6 @@ OpFunctionEnd SinglePassRunAndCheck(test, test, true, false); } -TEST_F(ReduceLoadSizeTest, extract_with_no_index) { - const std::string test = - R"( - OpCapability ImageGatherExtended - OpExtension "" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %4 "P�Ma'" %12 %17 - OpExecutionMode %4 OriginUpperLeft - %void = OpTypeVoid - %3 = OpTypeFunction %void - %float = OpTypeFloat 32 - %_struct_7 = OpTypeStruct %float %float -%_ptr_Input__struct_7 = OpTypePointer Input %_struct_7 -%_ptr_Output__struct_7 = OpTypePointer Output %_struct_7 - %12 = OpVariable %_ptr_Input__struct_7 Input - %17 = OpVariable %_ptr_Output__struct_7 Output - %4 = OpFunction %void DontInline|Pure|Const %3 - %245 = OpLabel - %13 = OpLoad %_struct_7 %12 - %33 = OpCompositeExtract %_struct_7 %13 - OpReturn - OpFunctionEnd - )"; - - auto result = SinglePassRunAndDisassemble(test, true, true); - EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); -} - } // namespace } // namespace opt } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/opt/scalar_replacement_test.cpp b/3rdparty/spirv-tools/test/opt/scalar_replacement_test.cpp index 122807600..3cf46ca13 100644 --- a/3rdparty/spirv-tools/test/opt/scalar_replacement_test.cpp +++ b/3rdparty/spirv-tools/test/opt/scalar_replacement_test.cpp @@ -1899,37 +1899,6 @@ TEST_F(ScalarReplacementTest, RelaxedPrecisionMemberDecoration) { SinglePassRunAndMatch(text, true); } -TEST_F(ScalarReplacementTest, ExtractWithNoIndex) { - const std::string text = R"( -; CHECK: [[var1:%\w+]] = OpVariable %_ptr_Function_float Function -; CHECK: [[var2:%\w+]] = OpVariable %_ptr_Function_float Function -; CHECK: [[ld1:%\w+]] = OpLoad %float [[var1]] -; CHECK: [[ld2:%\w+]] = OpLoad %float [[var2]] -; CHECK: [[constr:%\w+]] = OpCompositeConstruct {{%\w+}} [[ld2]] [[ld1]] -; CHECK: OpCompositeExtract {{%\w+}} [[constr]] -OpCapability Shader -OpExtension "" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %1 "main" -OpExecutionMode %1 OriginUpperLeft -%void = OpTypeVoid -%3 = OpTypeFunction %void -%float = OpTypeFloat 32 -%_struct_5 = OpTypeStruct %float %float -%_ptr_Private__struct_5 = OpTypePointer Private %_struct_5 -%_ptr_Function__struct_5 = OpTypePointer Function %_struct_5 -%1 = OpFunction %void Inline %3 -%8 = OpLabel -%9 = OpVariable %_ptr_Function__struct_5 Function -%10 = OpLoad %_struct_5 %9 -%11 = OpCompositeExtract %_struct_5 %10 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndMatch(text, true); -} - } // namespace } // namespace opt } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/opt/vector_dce_test.cpp b/3rdparty/spirv-tools/test/opt/vector_dce_test.cpp index a978a07f9..594995c16 100644 --- a/3rdparty/spirv-tools/test/opt/vector_dce_test.cpp +++ b/3rdparty/spirv-tools/test/opt/vector_dce_test.cpp @@ -1158,74 +1158,6 @@ OpFunctionEnd SinglePassRunAndCheck(text, text, true, true); } -TEST_F(VectorDCETest, InsertWithNoIndices) { - const std::string text = R"( -; CHECK: OpEntryPoint Fragment {{%\w+}} "PSMain" [[in1:%\w+]] [[in2:%\w+]] [[out:%\w+]] -; CHECK: OpFunction -; CHECK: [[ld:%\w+]] = OpLoad %v4float [[in2]] -; CHECK: OpStore [[out]] [[ld]] - OpCapability Shader - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %1 "PSMain" %2 %14 %3 - OpExecutionMode %1 OriginUpperLeft - %void = OpTypeVoid - %5 = OpTypeFunction %void - %float = OpTypeFloat 32 - %v4float = OpTypeVector %float 4 -%_ptr_Input_v4float = OpTypePointer Input %v4float -%_ptr_Output_v4float = OpTypePointer Output %v4float - %2 = OpVariable %_ptr_Input_v4float Input - %14 = OpVariable %_ptr_Input_v4float Input - %3 = OpVariable %_ptr_Output_v4float Output - %1 = OpFunction %void None %5 - %10 = OpLabel - %13 = OpLoad %v4float %14 - %11 = OpLoad %v4float %2 - %12 = OpCompositeInsert %v4float %13 %11 - OpStore %3 %12 - OpReturn - OpFunctionEnd -)"; - - SinglePassRunAndMatch(text, true); -} - -TEST_F(VectorDCETest, ExtractWithNoIndices) { - const std::string text = R"( -; CHECK: OpLoad %float -; CHECK: [[ld:%\w+]] = OpLoad %v4float -; CHECK: [[ex1:%\w+]] = OpCompositeExtract %v4float [[ld]] -; CHECK: [[ex2:%\w+]] = OpCompositeExtract %float [[ex1]] 1 -; CHECK: OpStore {{%\w+}} [[ex2]] - OpCapability Shader - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %1 "PSMain" %2 %14 %3 - OpExecutionMode %1 OriginUpperLeft - %void = OpTypeVoid - %5 = OpTypeFunction %void - %float = OpTypeFloat 32 - %v4float = OpTypeVector %float 4 -%_ptr_Input_float = OpTypePointer Input %float -%_ptr_Input_v4float = OpTypePointer Input %v4float -%_ptr_Output_float = OpTypePointer Output %float - %2 = OpVariable %_ptr_Input_v4float Input - %14 = OpVariable %_ptr_Input_float Input - %3 = OpVariable %_ptr_Output_float Output - %1 = OpFunction %void None %5 - %10 = OpLabel - %13 = OpLoad %float %14 - %11 = OpLoad %v4float %2 - %12 = OpCompositeInsert %v4float %13 %11 0 - %20 = OpCompositeExtract %v4float %12 - %21 = OpCompositeExtract %float %20 1 - OpStore %3 %21 - OpReturn - OpFunctionEnd -)"; - - SinglePassRunAndMatch(text, true); -} - } // namespace } // namespace opt } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/util/CMakeLists.txt b/3rdparty/spirv-tools/test/util/CMakeLists.txt index 8cdb35f42..6679dba7c 100644 --- a/3rdparty/spirv-tools/test/util/CMakeLists.txt +++ b/3rdparty/spirv-tools/test/util/CMakeLists.txt @@ -15,6 +15,7 @@ add_spvtools_unittest(TARGET utils SRCS ilist_test.cpp bit_vector_test.cpp + bitutils_test.cpp small_vector_test.cpp LIBS SPIRV-Tools-opt ) diff --git a/3rdparty/spirv-tools/test/util/bitutils_test.cpp b/3rdparty/spirv-tools/test/util/bitutils_test.cpp new file mode 100644 index 000000000..3be7ed269 --- /dev/null +++ b/3rdparty/spirv-tools/test/util/bitutils_test.cpp @@ -0,0 +1,193 @@ +// Copyright (c) 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/util/bitutils.h" + +#include "gmock/gmock.h" + +namespace spvtools { +namespace utils { +namespace { + +using BitUtilsTest = ::testing::Test; + +TEST(BitUtilsTest, MutateBitsWholeWord) { + const uint32_t zero_u32 = 0; + const uint32_t max_u32 = ~0; + + EXPECT_EQ(MutateBits(zero_u32, 0, 0, false), zero_u32); + EXPECT_EQ(MutateBits(max_u32, 0, 0, false), max_u32); + EXPECT_EQ(MutateBits(zero_u32, 0, 32, false), zero_u32); + EXPECT_EQ(MutateBits(zero_u32, 0, 32, true), max_u32); + EXPECT_EQ(MutateBits(max_u32, 0, 32, true), max_u32); + EXPECT_EQ(MutateBits(max_u32, 0, 32, false), zero_u32); +} + +TEST(BitUtilsTest, MutateBitsLow) { + const uint32_t zero_u32 = 0; + const uint32_t one_u32 = 1; + const uint32_t max_u32 = ~0; + + EXPECT_EQ(MutateBits(zero_u32, 0, 1, false), zero_u32); + EXPECT_EQ(MutateBits(zero_u32, 0, 1, true), one_u32); + EXPECT_EQ(MutateBits(max_u32, 0, 1, true), max_u32); + EXPECT_EQ(MutateBits(one_u32, 0, 32, false), zero_u32); + EXPECT_EQ(MutateBits(one_u32, 0, 1, true), one_u32); + EXPECT_EQ(MutateBits(one_u32, 0, 1, false), zero_u32); + EXPECT_EQ(MutateBits(zero_u32, 0, 3, true), uint32_t(7)); + EXPECT_EQ(MutateBits(uint32_t(7), 0, 2, false), uint32_t(4)); +} + +TEST(BitUtilsTest, MutateBitsHigh) { + const uint8_t zero_u8 = 0; + const uint8_t one_u8 = 1; + const uint8_t max_u8 = 255; + + EXPECT_EQ(MutateBits(zero_u8, 7, 0, true), zero_u8); + EXPECT_EQ(MutateBits(zero_u8, 7, 1, true), uint8_t(128)); + EXPECT_EQ(MutateBits(one_u8, 7, 1, true), uint8_t(129)); + EXPECT_EQ(MutateBits(max_u8, 7, 1, true), max_u8); + EXPECT_EQ(MutateBits(max_u8, 7, 1, false), uint8_t(127)); + EXPECT_EQ(MutateBits(max_u8, 6, 2, true), max_u8); + EXPECT_EQ(MutateBits(max_u8, 6, 2, false), uint8_t(63)); +} + +TEST(BitUtilsTest, MutateBitsUint8Mid) { + const uint8_t zero_u8 = 0; + const uint8_t max_u8 = 255; + + EXPECT_EQ(MutateBits(zero_u8, 1, 2, true), uint8_t(6)); + EXPECT_EQ(MutateBits(max_u8, 1, 2, true), max_u8); + EXPECT_EQ(MutateBits(max_u8, 1, 2, false), uint8_t(0xF9)); + EXPECT_EQ(MutateBits(zero_u8, 2, 3, true), uint8_t(0x1C)); +} + +TEST(BitUtilsTest, MutateBitsUint64Mid) { + const uint64_t zero_u64 = 0; + const uint64_t max_u64 = ~zero_u64; + + EXPECT_EQ(MutateBits(zero_u64, 1, 2, true), uint64_t(6)); + EXPECT_EQ(MutateBits(max_u64, 1, 2, true), max_u64); + EXPECT_EQ(MutateBits(max_u64, 1, 2, false), uint64_t(0xFFFFFFFFFFFFFFF9)); + EXPECT_EQ(MutateBits(zero_u64, 2, 3, true), uint64_t(0x000000000000001C)); + EXPECT_EQ(MutateBits(zero_u64, 2, 35, true), uint64_t(0x0000001FFFFFFFFC)); + EXPECT_EQ(MutateBits(zero_u64, 36, 4, true), uint64_t(0x000000F000000000)); + EXPECT_EQ(MutateBits(max_u64, 36, 4, false), uint64_t(0xFFFFFF0FFFFFFFFF)); +} + +TEST(BitUtilsTest, SetHighBitsUint32) { + const uint32_t zero_u32 = 0; + const uint32_t one_u32 = 1; + const uint32_t max_u32 = ~zero_u32; + + EXPECT_EQ(SetHighBits(zero_u32, 0), zero_u32); + EXPECT_EQ(SetHighBits(zero_u32, 1), 0x80000000); + EXPECT_EQ(SetHighBits(one_u32, 1), 0x80000001); + EXPECT_EQ(SetHighBits(one_u32, 2), 0xC0000001); + EXPECT_EQ(SetHighBits(zero_u32, 31), 0xFFFFFFFE); + EXPECT_EQ(SetHighBits(zero_u32, 32), max_u32); + EXPECT_EQ(SetHighBits(max_u32, 32), max_u32); +} + +TEST(BitUtilsTest, ClearHighBitsUint32) { + const uint32_t zero_u32 = 0; + const uint32_t one_u32 = 1; + const uint32_t max_u32 = ~zero_u32; + + EXPECT_EQ(ClearHighBits(zero_u32, 0), zero_u32); + EXPECT_EQ(ClearHighBits(zero_u32, 1), zero_u32); + EXPECT_EQ(ClearHighBits(one_u32, 1), one_u32); + EXPECT_EQ(ClearHighBits(one_u32, 31), one_u32); + EXPECT_EQ(ClearHighBits(one_u32, 32), zero_u32); + EXPECT_EQ(ClearHighBits(max_u32, 0), max_u32); + EXPECT_EQ(ClearHighBits(max_u32, 1), 0x7FFFFFFF); + EXPECT_EQ(ClearHighBits(max_u32, 2), 0x3FFFFFFF); + EXPECT_EQ(ClearHighBits(max_u32, 31), one_u32); + EXPECT_EQ(ClearHighBits(max_u32, 32), zero_u32); +} + +TEST(BitUtilsTest, IsBitSetAtPositionZero) { + const uint32_t zero_u32 = 0; + for (size_t i = 0; i != 32; ++i) { + EXPECT_FALSE(IsBitAtPositionSet(zero_u32, i)); + } + + const uint8_t zero_u8 = 0; + for (size_t i = 0; i != 8; ++i) { + EXPECT_FALSE(IsBitAtPositionSet(zero_u8, i)); + } + + const uint64_t zero_u64 = 0; + for (size_t i = 0; i != 64; ++i) { + EXPECT_FALSE(IsBitAtPositionSet(zero_u64, i)); + } +} + +TEST(BitUtilsTest, IsBitSetAtPositionOne) { + const uint32_t one_u32 = 1; + for (size_t i = 0; i != 32; ++i) { + if (i == 0) { + EXPECT_TRUE(IsBitAtPositionSet(one_u32, i)); + } else { + EXPECT_FALSE(IsBitAtPositionSet(one_u32, i)); + } + } + + const uint32_t two_to_17_u32 = 1 << 17; + for (size_t i = 0; i != 32; ++i) { + if (i == 17) { + EXPECT_TRUE(IsBitAtPositionSet(two_to_17_u32, i)); + } else { + EXPECT_FALSE(IsBitAtPositionSet(two_to_17_u32, i)); + } + } + + const uint8_t two_to_4_u8 = 1 << 4; + for (size_t i = 0; i != 8; ++i) { + if (i == 4) { + EXPECT_TRUE(IsBitAtPositionSet(two_to_4_u8, i)); + } else { + EXPECT_FALSE(IsBitAtPositionSet(two_to_4_u8, i)); + } + } + + const uint64_t two_to_55_u64 = uint64_t(1) << 55; + for (size_t i = 0; i != 64; ++i) { + if (i == 55) { + EXPECT_TRUE(IsBitAtPositionSet(two_to_55_u64, i)); + } else { + EXPECT_FALSE(IsBitAtPositionSet(two_to_55_u64, i)); + } + } +} + +TEST(BitUtilsTest, IsBitSetAtPositionAll) { + const uint32_t max_u32 = ~0; + for (size_t i = 0; i != 32; ++i) { + EXPECT_TRUE(IsBitAtPositionSet(max_u32, i)); + } + + const uint32_t max_u8 = ~uint8_t(0); + for (size_t i = 0; i != 8; ++i) { + EXPECT_TRUE(IsBitAtPositionSet(max_u8, i)); + } + + const uint64_t max_u64 = ~uint64_t(0); + for (size_t i = 0; i != 64; ++i) { + EXPECT_TRUE(IsBitAtPositionSet(max_u64, i)); + } +} +} // namespace +} // namespace utils +} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/val/val_composites_test.cpp b/3rdparty/spirv-tools/test/val/val_composites_test.cpp index 74b6f2095..e97056211 100644 --- a/3rdparty/spirv-tools/test/val/val_composites_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_composites_test.cpp @@ -648,7 +648,6 @@ TEST_F(ValidateComposites, CompositeExtractSuccess) { %val16 = OpCompositeExtract %f32 %struct 4 1000 1 %val17 = OpCompositeExtract %f32 %struct 5 0 %val18 = OpCompositeExtract %u32 %struct 5 1 -%val19 = OpCompositeExtract %big_struct %struct )"; CompileSuccessfully(GenerateShaderCode(body)); @@ -767,6 +766,18 @@ TEST_F(ValidateComposites, CompositeExtractTooManyIndices) { "indexes still remain to be traversed.")); } +TEST_F(ValidateComposites, CompositeExtractNoIndices) { + const std::string body = R"( +%struct = OpLoad %big_struct %var_big_struct +%val1 = OpCompositeExtract %big_struct %struct +)"; + + CompileSuccessfully(GenerateShaderCode(body)); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected at least one index to OpCompositeExtract")); +} + TEST_F(ValidateComposites, CompositeExtractWrongType1) { const std::string body = R"( %struct = OpLoad %big_struct %var_big_struct @@ -861,7 +872,6 @@ TEST_F(ValidateComposites, CompositeInsertSuccess) { %val16 = OpCompositeInsert %big_struct %f32_3 %struct 4 1000 1 %val17 = OpCompositeInsert %big_struct %f32_3 %struct 5 0 %val18 = OpCompositeInsert %big_struct %u32_3 %struct 5 1 -%val19 = OpCompositeInsert %big_struct %struct %struct )"; CompileSuccessfully(GenerateShaderCode(body)); @@ -1157,9 +1167,8 @@ TEST_F(ValidateComposites, CompositeInsertWrongResultTypeBad) { HasSubstr("The Result Type must be the same as Composite type")); } -// Valid: No Indexes were passed to OpCompositeExtract, and the Result Type is -// the same as the Base Composite type. -TEST_F(ValidateComposites, CompositeExtractNoIndexesGood) { +// Invalid: No Indexes were passed to OpCompositeExtract. +TEST_F(ValidateComposites, CompositeExtractNoIndices2) { std::ostringstream spirv; spirv << GetHeaderForTestsFromValId() << std::endl; spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl; @@ -1167,29 +1176,32 @@ TEST_F(ValidateComposites, CompositeExtractNoIndexesGood) { spirv << R"(OpReturn OpFunctionEnd)"; CompileSuccessfully(spirv.str()); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Expected at least one index to OpCompositeExtract, zero found")); } -// Invalid: No Indexes were passed to OpCompositeExtract, but the Result Type is -// different from the Base Composite type. -TEST_F(ValidateComposites, CompositeExtractNoIndexesBad) { +// Invalid: No Indexes were passed to OpCompositeExtract. +TEST_F(ValidateComposites, CompositeExtractNoIndicesWrongResultType) { std::ostringstream spirv; spirv << GetHeaderForTestsFromValId() << std::endl; spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl; - spirv << "%float_entry = OpCompositeExtract %float %matrix" << std::endl; + spirv << "%float_entry = OpCompositeExtract %float %matrix" << std::endl; spirv << R"(OpReturn OpFunctionEnd)"; CompileSuccessfully(spirv.str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Result type (OpTypeFloat) does not match the type " - "that results from indexing into the composite " - "(OpTypeMatrix).")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Expected at least one index to OpCompositeExtract, zero found")); } -// Valid: No Indexes were passed to OpCompositeInsert, and the type of the +// Invalid: No Indices were passed to OpCompositeInsert, and the type of the // Object argument matches the Composite type. -TEST_F(ValidateComposites, CompositeInsertMissingIndexesGood) { +TEST_F(ValidateComposites, CompositeInsertMissingIndices) { std::ostringstream spirv; spirv << GetHeaderForTestsFromValId() << std::endl; spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl; @@ -1199,12 +1211,16 @@ TEST_F(ValidateComposites, CompositeInsertMissingIndexesGood) { OpReturn OpFunctionEnd)"; CompileSuccessfully(spirv.str()); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Expected at least one index to OpCompositeInsert, zero found")); } -// Invalid: No Indexes were passed to OpCompositeInsert, but the type of the +// Invalid: No Indices were passed to OpCompositeInsert, but the type of the // Object argument does not match the Composite type. -TEST_F(ValidateComposites, CompositeInsertMissingIndexesBad) { +TEST_F(ValidateComposites, CompositeInsertMissingIndices2) { std::ostringstream spirv; spirv << GetHeaderForTestsFromValId() << std::endl; spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl; @@ -1214,10 +1230,10 @@ TEST_F(ValidateComposites, CompositeInsertMissingIndexesBad) { OpFunctionEnd)"; CompileSuccessfully(spirv.str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("The Object type (OpTypeInt) does not match the type " - "that results from indexing into the Composite " - "(OpTypeMatrix).")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Expected at least one index to OpCompositeInsert, zero found")); } // Valid: Tests that we can index into Struct, Array, Matrix, and Vector! diff --git a/3rdparty/spirv-tools/test/val/val_derivatives_test.cpp b/3rdparty/spirv-tools/test/val/val_derivatives_test.cpp index dac95f6eb..606abb93d 100644 --- a/3rdparty/spirv-tools/test/val/val_derivatives_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_derivatives_test.cpp @@ -62,7 +62,17 @@ OpCapability DerivativeControl %f32vec4_ptr_input = OpTypePointer Input %f32vec4 %f32vec4_var_input = OpVariable %f32vec4_ptr_input Input +)"; + if (capabilities_and_extensions.find("OpCapability Float16") != + std::string::npos) { + ss << "%f16 = OpTypeFloat 16\n" + << "%f16vec4 = OpTypeVector %f16 4\n" + << "%f16_0 = OpConstantNull %f16\n" + << "%f16vec4_0 = OpConstantNull %f16vec4\n"; + } + + ss << R"( %main = OpFunction %void None %func %main_entry = OpLabel )"; @@ -150,6 +160,36 @@ TEST_F(ValidateDerivatives, OpDPdxWrongExecutionModel) { "execution model: DPdx")); } +using ValidateHalfDerivatives = spvtest::ValidateBase; + +TEST_P(ValidateHalfDerivatives, ScalarFailure) { + const std::string op = GetParam(); + const std::string body = "%val = " + op + " %f16 %f16_0\n"; + + CompileSuccessfully( + GenerateShaderCode(body, "OpCapability Float16\n").c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Result type component width must be 32 bits")); +} + +TEST_P(ValidateHalfDerivatives, VectorFailure) { + const std::string op = GetParam(); + const std::string body = "%val = " + op + " %f16vec4 %f16vec4_0\n"; + + CompileSuccessfully( + GenerateShaderCode(body, "OpCapability Float16\n").c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Result type component width must be 32 bits")); +} + +INSTANTIATE_TEST_SUITE_P(HalfDerivatives, ValidateHalfDerivatives, + ::testing::Values("OpDPdx", "OpDPdy", "OpFwidth", + "OpDPdxFine", "OpDPdyFine", + "OpFwidthFine", "OpDPdxCoarse", + "OpDPdyCoarse", "OpFwidthCoarse")); + } // namespace } // namespace val } // namespace spvtools diff --git a/3rdparty/spirv-tools/utils/update_build_version.py b/3rdparty/spirv-tools/utils/update_build_version.py index 119bb054f..e8ef52f10 100755 --- a/3rdparty/spirv-tools/utils/update_build_version.py +++ b/3rdparty/spirv-tools/utils/update_build_version.py @@ -119,7 +119,7 @@ def describe(directory): # clock time with enviornment variable SOURCE_DATE_EPOCH # containing a (presumably) fixed timestamp. timestamp = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) - formatted = datetime.date.fromtimestamp(timestamp).isoformat() + formatted = datetime.datetime.utcfromtimestamp(timestamp).isoformat() return 'unknown hash, {}'.format(formatted)