diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index b04070ca6..49fb2f5db 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2023.2", "SPIRV-Tools v2023.2 v2022.4-192-ge472626b" +"v2023.2", "SPIRV-Tools v2023.2 v2022.4-196-g1b88382e" diff --git a/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp b/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp index 51a65245f..16456386b 100644 --- a/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp @@ -156,7 +156,8 @@ bool AggressiveDCEPass::AllExtensionsSupported() const { "Expecting an import of an extension's instruction set."); const std::string extension_name = inst.GetInOperand(0).AsString(); if (spvtools::utils::starts_with(extension_name, "NonSemantic.") && - extension_name != "NonSemantic.Shader.DebugInfo.100") { + (extension_name != "NonSemantic.Shader.DebugInfo.100") && + (extension_name != "NonSemantic.DebugPrintf")) { return false; } } diff --git a/3rdparty/spirv-tools/source/opt/convert_to_half_pass.cpp b/3rdparty/spirv-tools/source/opt/convert_to_half_pass.cpp index 7a4c1f409..2c4a631e1 100644 --- a/3rdparty/spirv-tools/source/opt/convert_to_half_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/convert_to_half_pass.cpp @@ -39,6 +39,13 @@ bool ConvertToHalfPass::IsFloat(Instruction* inst, uint32_t width) { return Pass::IsFloat(ty_id, width); } +bool ConvertToHalfPass::IsStruct(Instruction* inst) { + uint32_t ty_id = inst->type_id(); + if (ty_id == 0) return false; + Instruction* ty_inst = Pass::GetBaseType(ty_id); + return (ty_inst->opcode() == spv::Op::OpTypeStruct); +} + bool ConvertToHalfPass::IsDecoratedRelaxed(Instruction* inst) { uint32_t r_id = inst->result_id(); for (auto r_inst : get_decoration_mgr()->GetDecorationsFor(r_id, false)) @@ -294,6 +301,7 @@ bool ConvertToHalfPass::CloseRelaxInst(Instruction* inst) { bool relax = true; inst->ForEachInId([&relax, this](uint32_t* idp) { Instruction* op_inst = get_def_use_mgr()->GetDef(*idp); + if (IsStruct(op_inst)) relax = false; if (!IsFloat(op_inst, 32)) return; if (!IsRelaxed(*idp)) relax = false; }); diff --git a/3rdparty/spirv-tools/source/opt/convert_to_half_pass.h b/3rdparty/spirv-tools/source/opt/convert_to_half_pass.h index feabfba3e..24a478ffc 100644 --- a/3rdparty/spirv-tools/source/opt/convert_to_half_pass.h +++ b/3rdparty/spirv-tools/source/opt/convert_to_half_pass.h @@ -45,6 +45,7 @@ class ConvertToHalfPass : public Pass { // Return true if |inst| returns scalar, vector or matrix type with base // float and |width| bool IsFloat(Instruction* inst, uint32_t width); + bool IsStruct(Instruction* inst); // Return true if |inst| is decorated with RelaxedPrecision bool IsDecoratedRelaxed(Instruction* inst); diff --git a/3rdparty/spirv-tools/source/opt/scalar_replacement_pass.cpp b/3rdparty/spirv-tools/source/opt/scalar_replacement_pass.cpp index ae1a2a363..38c8aeccc 100644 --- a/3rdparty/spirv-tools/source/opt/scalar_replacement_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/scalar_replacement_pass.cpp @@ -466,9 +466,9 @@ void ScalarReplacementPass::TransferAnnotations( } void ScalarReplacementPass::CreateVariable( - uint32_t typeId, Instruction* varInst, uint32_t index, + uint32_t type_id, Instruction* var_inst, uint32_t index, std::vector* replacements) { - uint32_t ptrId = GetOrCreatePointerType(typeId); + uint32_t ptr_id = GetOrCreatePointerType(type_id); uint32_t id = TakeNextId(); if (id == 0) { @@ -476,51 +476,22 @@ void ScalarReplacementPass::CreateVariable( } std::unique_ptr variable( - new Instruction(context(), spv::Op::OpVariable, ptrId, id, + new Instruction(context(), spv::Op::OpVariable, ptr_id, id, std::initializer_list{ {SPV_OPERAND_TYPE_STORAGE_CLASS, {uint32_t(spv::StorageClass::Function)}}})); - BasicBlock* block = context()->get_instr_block(varInst); + BasicBlock* block = context()->get_instr_block(var_inst); block->begin().InsertBefore(std::move(variable)); Instruction* inst = &*block->begin(); // If varInst was initialized, make sure to initialize its replacement. - GetOrCreateInitialValue(varInst, index, inst); + GetOrCreateInitialValue(var_inst, index, inst); get_def_use_mgr()->AnalyzeInstDefUse(inst); context()->set_instr_block(inst, block); - // Copy decorations from the member to the new variable. - Instruction* typeInst = GetStorageType(varInst); - for (auto dec_inst : - get_decoration_mgr()->GetDecorationsFor(typeInst->result_id(), false)) { - uint32_t decoration; - if (dec_inst->opcode() != spv::Op::OpMemberDecorate) { - continue; - } - - if (dec_inst->GetSingleWordInOperand(1) != index) { - continue; - } - - decoration = dec_inst->GetSingleWordInOperand(2u); - switch (spv::Decoration(decoration)) { - case spv::Decoration::RelaxedPrecision: { - std::unique_ptr new_dec_inst( - new Instruction(context(), spv::Op::OpDecorate, 0, 0, {})); - new_dec_inst->AddOperand(Operand(SPV_OPERAND_TYPE_ID, {id})); - for (uint32_t i = 2; i < dec_inst->NumInOperandWords(); ++i) { - new_dec_inst->AddOperand(Operand(dec_inst->GetInOperand(i))); - } - context()->AddAnnotationInst(std::move(new_dec_inst)); - } break; - default: - break; - } - } - - // Update the DebugInfo debug information. - inst->UpdateDebugInfoFrom(varInst); + CopyDecorationsToVariable(var_inst, inst, index); + inst->UpdateDebugInfoFrom(var_inst); replacements->push_back(inst); } @@ -529,52 +500,11 @@ uint32_t ScalarReplacementPass::GetOrCreatePointerType(uint32_t id) { auto iter = pointee_to_pointer_.find(id); if (iter != pointee_to_pointer_.end()) return iter->second; - analysis::Type* pointeeTy; - std::unique_ptr pointerTy; - std::tie(pointeeTy, pointerTy) = - context()->get_type_mgr()->GetTypeAndPointerType( - id, spv::StorageClass::Function); - uint32_t ptrId = 0; - if (pointeeTy->IsUniqueType()) { - // Non-ambiguous type, just ask the type manager for an id. - ptrId = context()->get_type_mgr()->GetTypeInstruction(pointerTy.get()); - pointee_to_pointer_[id] = ptrId; - return ptrId; - } - - // Ambiguous type. We must perform a linear search to try and find the right - // type. - for (auto global : context()->types_values()) { - if (global.opcode() == spv::Op::OpTypePointer && - spv::StorageClass(global.GetSingleWordInOperand(0u)) == - spv::StorageClass::Function && - global.GetSingleWordInOperand(1u) == id) { - if (get_decoration_mgr()->GetDecorationsFor(id, false).empty()) { - // Only reuse a decoration-less pointer of the correct type. - ptrId = global.result_id(); - break; - } - } - } - - if (ptrId != 0) { - pointee_to_pointer_[id] = ptrId; - return ptrId; - } - - ptrId = TakeNextId(); - context()->AddType(MakeUnique( - context(), spv::Op::OpTypePointer, 0, ptrId, - std::initializer_list{{SPV_OPERAND_TYPE_STORAGE_CLASS, - {uint32_t(spv::StorageClass::Function)}}, - {SPV_OPERAND_TYPE_ID, {id}}})); - Instruction* ptr = &*--context()->types_values_end(); - get_def_use_mgr()->AnalyzeInstDefUse(ptr); - pointee_to_pointer_[id] = ptrId; - // Register with the type manager if necessary. - context()->get_type_mgr()->RegisterType(ptrId, *pointerTy); - - return ptrId; + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + uint32_t ptr_type_id = + type_mgr->FindPointerToType(id, spv::StorageClass::Function); + pointee_to_pointer_[id] = ptr_type_id; + return ptr_type_id; } void ScalarReplacementPass::GetOrCreateInitialValue(Instruction* source, @@ -761,6 +691,8 @@ bool ScalarReplacementPass::CheckTypeAnnotations( case spv::Decoration::AlignmentId: case spv::Decoration::MaxByteOffset: case spv::Decoration::RelaxedPrecision: + case spv::Decoration::AliasedPointer: + case spv::Decoration::RestrictPointer: break; default: return false; @@ -781,6 +713,8 @@ bool ScalarReplacementPass::CheckAnnotations(const Instruction* varInst) const { case spv::Decoration::Alignment: case spv::Decoration::AlignmentId: case spv::Decoration::MaxByteOffset: + case spv::Decoration::AliasedPointer: + case spv::Decoration::RestrictPointer: break; default: return false; @@ -1011,5 +945,69 @@ uint64_t ScalarReplacementPass::GetMaxLegalIndex( return 0; } +void ScalarReplacementPass::CopyDecorationsToVariable(Instruction* from, + Instruction* to, + uint32_t member_index) { + CopyPointerDecorationsToVariable(from, to); + CopyNecessaryMemberDecorationsToVariable(from, to, member_index); +} + +void ScalarReplacementPass::CopyPointerDecorationsToVariable(Instruction* from, + Instruction* to) { + // The RestrictPointer and AliasedPointer decorations are copied to all + // members even if the new variable does not contain a pointer. It does + // not hurt to do so. + for (auto dec_inst : + get_decoration_mgr()->GetDecorationsFor(from->result_id(), false)) { + uint32_t decoration; + decoration = dec_inst->GetSingleWordInOperand(1u); + switch (spv::Decoration(decoration)) { + case spv::Decoration::AliasedPointer: + case spv::Decoration::RestrictPointer: { + std::unique_ptr new_dec_inst(dec_inst->Clone(context())); + new_dec_inst->SetInOperand(0, {to->result_id()}); + context()->AddAnnotationInst(std::move(new_dec_inst)); + } break; + default: + break; + } + } +} + +void ScalarReplacementPass::CopyNecessaryMemberDecorationsToVariable( + Instruction* from, Instruction* to, uint32_t member_index) { + Instruction* type_inst = GetStorageType(from); + for (auto dec_inst : + get_decoration_mgr()->GetDecorationsFor(type_inst->result_id(), false)) { + uint32_t decoration; + if (dec_inst->opcode() == spv::Op::OpMemberDecorate) { + if (dec_inst->GetSingleWordInOperand(1) != member_index) { + continue; + } + + decoration = dec_inst->GetSingleWordInOperand(2u); + switch (spv::Decoration(decoration)) { + case spv::Decoration::ArrayStride: + case spv::Decoration::Alignment: + case spv::Decoration::AlignmentId: + case spv::Decoration::MaxByteOffset: + case spv::Decoration::MaxByteOffsetId: + case spv::Decoration::RelaxedPrecision: { + std::unique_ptr new_dec_inst( + new Instruction(context(), spv::Op::OpDecorate, 0, 0, {})); + new_dec_inst->AddOperand( + Operand(SPV_OPERAND_TYPE_ID, {to->result_id()})); + for (uint32_t i = 2; i < dec_inst->NumInOperandWords(); ++i) { + new_dec_inst->AddOperand(Operand(dec_inst->GetInOperand(i))); + } + context()->AddAnnotationInst(std::move(new_dec_inst)); + } break; + default: + break; + } + } + } +} + } // namespace opt } // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/scalar_replacement_pass.h b/3rdparty/spirv-tools/source/opt/scalar_replacement_pass.h index 0bcd2a4e4..c73ecfd98 100644 --- a/3rdparty/spirv-tools/source/opt/scalar_replacement_pass.h +++ b/3rdparty/spirv-tools/source/opt/scalar_replacement_pass.h @@ -262,9 +262,26 @@ class ScalarReplacementPass : public MemPass { // that we will be willing to split. bool IsLargerThanSizeLimit(uint64_t length) const; + // Copies all relevant decorations from `from` to `to`. This includes + // decorations applied to the variable, and to the members of the type. + // It is assumed that `to` is a variable that is intended to replace the + // `member_index`th member of `from`. + void CopyDecorationsToVariable(Instruction* from, Instruction* to, + uint32_t member_index); + + // Copies pointer related decoration from `from` to `to` if they exist. + void CopyPointerDecorationsToVariable(Instruction* from, Instruction* to); + + // Copies decorations that are needed from the `member_index` of `from` to + // `to, if there was one. + void CopyNecessaryMemberDecorationsToVariable(Instruction* from, + Instruction* to, + uint32_t member_index); + // Limit on the number of members in an object that will be replaced. // 0 means there is no limit. uint32_t max_num_elements_; + // This has to be big enough to fit "scalar-replacement=" followed by a // uint32_t number written in decimal (so 10 digits), and then a // terminating nul. diff --git a/3rdparty/spirv-tools/source/opt/type_manager.cpp b/3rdparty/spirv-tools/source/opt/type_manager.cpp index 6e4c054ef..1b1aeadc8 100644 --- a/3rdparty/spirv-tools/source/opt/type_manager.cpp +++ b/3rdparty/spirv-tools/source/opt/type_manager.cpp @@ -178,7 +178,7 @@ void TypeManager::RemoveId(uint32_t id) { if (iter == id_to_type_.end()) return; auto& type = iter->second; - if (!type->IsUniqueType(true)) { + if (!type->IsUniqueType()) { auto tIter = type_to_id_.find(type); if (tIter != type_to_id_.end() && tIter->second == id) { // |type| currently maps to |id|. @@ -437,7 +437,7 @@ uint32_t TypeManager::FindPointerToType(uint32_t type_id, spv::StorageClass storage_class) { Type* pointeeTy = GetType(type_id); Pointer pointerTy(pointeeTy, storage_class); - if (pointeeTy->IsUniqueType(true)) { + if (pointeeTy->IsUniqueType()) { // Non-ambiguous type. Get the pointer type through the type manager. return GetTypeInstruction(&pointerTy); } diff --git a/3rdparty/spirv-tools/source/opt/types.cpp b/3rdparty/spirv-tools/source/opt/types.cpp index 2f1836281..49eec9b74 100644 --- a/3rdparty/spirv-tools/source/opt/types.cpp +++ b/3rdparty/spirv-tools/source/opt/types.cpp @@ -84,10 +84,9 @@ bool Type::HasSameDecorations(const Type* that) const { return CompareTwoVectors(decorations_, that->decorations_); } -bool Type::IsUniqueType(bool allowVariablePointers) const { +bool Type::IsUniqueType() const { switch (kind_) { case kPointer: - return !allowVariablePointers; case kStruct: case kArray: case kRuntimeArray: diff --git a/3rdparty/spirv-tools/source/opt/types.h b/3rdparty/spirv-tools/source/opt/types.h index 1f329373b..26c058c6f 100644 --- a/3rdparty/spirv-tools/source/opt/types.h +++ b/3rdparty/spirv-tools/source/opt/types.h @@ -148,12 +148,16 @@ class Type { // Returns a clone of |this| minus any decorations. std::unique_ptr RemoveDecorations() const; - // Returns true if this type must be unique. + // Returns true if this cannot hash to the same value as another type in the + // module. For example, structs are not unique types because the module could + // have two types // - // If variable pointers are allowed, then pointers are not required to be - // unique. - // TODO(alanbaker): Update this if variable pointers become a core feature. - bool IsUniqueType(bool allowVariablePointers = false) const; + // %1 = OpTypeStruct %int + // %2 = OpTypeStruct %int + // + // The only way to distinguish these types is the result id. The type manager + // will hash them to the same value. + bool IsUniqueType() const; bool operator==(const Type& other) const;