mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-26 21:30:07 +00:00
Handle decoration groups with no decorations. (#1921)
In DecorationManager::RemoveDecorationsFrom, we do not remove the id from a decoration group if the group has no decorations. This causes problems because KillNamesAndDecorates is suppose to remove all references to the id, but in this case, there is still a reference. This is fixed by adding a special case. Also, there is the possibility of a double free because RemoveDecorationsFrom will delete the instructions defining |id| when |id| is a decoration group. Later, KillInst would later write to memory that has been deleted when trying to turn it into a Nop. To fix this, we will only remove the decorations that use |id| and not its definition in RemoveDecorationsFrom.
This commit is contained in:
parent
f0aa6f4e3a
commit
32381e30ef
@ -29,7 +29,9 @@ namespace analysis {
|
|||||||
void DecorationManager::RemoveDecorationsFrom(
|
void DecorationManager::RemoveDecorationsFrom(
|
||||||
uint32_t id, std::function<bool(const Instruction&)> pred) {
|
uint32_t id, std::function<bool(const Instruction&)> pred) {
|
||||||
const auto ids_iter = id_to_decoration_insts_.find(id);
|
const auto ids_iter = id_to_decoration_insts_.find(id);
|
||||||
if (ids_iter == id_to_decoration_insts_.end()) return;
|
if (ids_iter == id_to_decoration_insts_.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TargetData& decorations_info = ids_iter->second;
|
TargetData& decorations_info = ids_iter->second;
|
||||||
auto context = module_->context();
|
auto context = module_->context();
|
||||||
@ -59,8 +61,14 @@ void DecorationManager::RemoveDecorationsFrom(
|
|||||||
if (!pred(*decoration)) group_decorations_to_keep.push_back(decoration);
|
if (!pred(*decoration)) group_decorations_to_keep.push_back(decoration);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If all decorations should be kept, move to the next group
|
// If all decorations should be kept, then we can keep |id| part of the
|
||||||
if (group_decorations_to_keep.size() == group_decorations.size()) continue;
|
// group. However, if the group itself has no decorations, we should remove
|
||||||
|
// the id from the group. This is needed to make |KillNameAndDecorate| work
|
||||||
|
// correctly when a decoration group has no decorations.
|
||||||
|
if (group_decorations_to_keep.size() == group_decorations.size() &&
|
||||||
|
group_decorations.size() != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Otherwise, remove |id| from the targets of |group_id|
|
// Otherwise, remove |id| from the targets of |group_id|
|
||||||
const uint32_t stride = inst->opcode() == SpvOpGroupDecorate ? 1u : 2u;
|
const uint32_t stride = inst->opcode() == SpvOpGroupDecorate ? 1u : 2u;
|
||||||
@ -136,9 +144,6 @@ void DecorationManager::RemoveDecorationsFrom(
|
|||||||
decorations_info.indirect_decorations.empty() &&
|
decorations_info.indirect_decorations.empty() &&
|
||||||
decorations_info.decorate_insts.empty()) {
|
decorations_info.decorate_insts.empty()) {
|
||||||
id_to_decoration_insts_.erase(ids_iter);
|
id_to_decoration_insts_.erase(ids_iter);
|
||||||
|
|
||||||
// Remove the OpDecorationGroup defining this group.
|
|
||||||
if (is_group) context->KillInst(context->get_def_use_mgr()->GetDef(id));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,11 +36,22 @@ class DecorationManager {
|
|||||||
}
|
}
|
||||||
DecorationManager() = delete;
|
DecorationManager() = delete;
|
||||||
|
|
||||||
// Removes all decorations from |id| (either directly or indirectly) for
|
// Changes all of the decorations (direct and through groups) where |pred| is
|
||||||
// which |pred| returns true.
|
// true and that apply to |id| so that they no longer apply to |id|.
|
||||||
// If |id| is a group ID, OpGroupDecorate and OpGroupMemberDecorate will be
|
//
|
||||||
// removed if they have no targets left, and OpDecorationGroup will be
|
// If |id| is part of a group, it will be removed from the group if it
|
||||||
// removed if the group is not applied to anyone and contains no decorations.
|
// does not use all of the group's decorations, or, if there are no
|
||||||
|
// decorations that apply to the group.
|
||||||
|
//
|
||||||
|
// If decoration groups become empty, the |OpGroupDecorate| and
|
||||||
|
// |OpGroupMemberDecorate| instructions will be killed.
|
||||||
|
//
|
||||||
|
// Decoration instructions that apply directly to |id| will be killed.
|
||||||
|
//
|
||||||
|
// If |id| is a decoration group and all of the group's decorations are
|
||||||
|
// removed, then the |OpGroupDecorate| and
|
||||||
|
// |OpGroupMemberDecorate| for the group will be killed, but not the defining
|
||||||
|
// |OpDecorationGroup| instruction.
|
||||||
void RemoveDecorationsFrom(uint32_t id,
|
void RemoveDecorationsFrom(uint32_t id,
|
||||||
std::function<bool(const Instruction&)> pred =
|
std::function<bool(const Instruction&)> pred =
|
||||||
[](const Instruction&) { return true; });
|
[](const Instruction&) { return true; });
|
||||||
|
@ -422,6 +422,7 @@ OpGroupDecorate %2 %1 %3
|
|||||||
OpCapability Linkage
|
OpCapability Linkage
|
||||||
OpMemoryModel Logical GLSL450
|
OpMemoryModel Logical GLSL450
|
||||||
OpDecorate %1 Constant
|
OpDecorate %1 Constant
|
||||||
|
%2 = OpDecorationGroup
|
||||||
%4 = OpTypeInt 32 0
|
%4 = OpTypeInt 32 0
|
||||||
%1 = OpVariable %4 Uniform
|
%1 = OpVariable %4 Uniform
|
||||||
%3 = OpVariable %4 Uniform
|
%3 = OpVariable %4 Uniform
|
||||||
|
@ -282,6 +282,94 @@ TEST_F(IRContextTest, TakeNextUniqueIdIncrementing) {
|
|||||||
EXPECT_EQ(i, localContext.TakeNextUniqueId());
|
EXPECT_EQ(i, localContext.TakeNextUniqueId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(IRContextTest, KillGroupDecorationWitNoDecorations) {
|
||||||
|
const std::string text = R"(
|
||||||
|
OpCapability Shader
|
||||||
|
%1 = OpExtInstImport "GLSL.std.450"
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint Fragment %2 "main"
|
||||||
|
OpExecutionMode %2 OriginUpperLeft
|
||||||
|
OpSource GLSL 430
|
||||||
|
%3 = OpDecorationGroup
|
||||||
|
OpGroupDecorate %3 %4 %5
|
||||||
|
%6 = OpTypeFloat 32
|
||||||
|
%7 = OpTypePointer Function %6
|
||||||
|
%8 = OpTypeStruct %6
|
||||||
|
%9 = OpTypeVoid
|
||||||
|
%10 = OpTypeFunction %9
|
||||||
|
%2 = OpFunction %9 None %10
|
||||||
|
%11 = OpLabel
|
||||||
|
%4 = OpVariable %7 Function
|
||||||
|
%5 = OpVariable %7 Function
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
std::unique_ptr<IRContext> context =
|
||||||
|
BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
||||||
|
|
||||||
|
// Build the decoration manager.
|
||||||
|
context->get_decoration_mgr();
|
||||||
|
|
||||||
|
// Delete the second variable.
|
||||||
|
context->KillDef(5);
|
||||||
|
|
||||||
|
// The two decoration instructions should still be there. The first one
|
||||||
|
// should be the same, but the second should have %5 removed.
|
||||||
|
|
||||||
|
// Check the OpDecorationGroup Instruction
|
||||||
|
auto inst = context->annotation_begin();
|
||||||
|
EXPECT_EQ(inst->opcode(), SpvOpDecorationGroup);
|
||||||
|
EXPECT_EQ(inst->result_id(), 3);
|
||||||
|
|
||||||
|
// Check that %5 is no longer part of the group.
|
||||||
|
++inst;
|
||||||
|
EXPECT_EQ(inst->opcode(), SpvOpGroupDecorate);
|
||||||
|
EXPECT_EQ(inst->NumInOperands(), 2);
|
||||||
|
EXPECT_EQ(inst->GetSingleWordInOperand(0), 3);
|
||||||
|
EXPECT_EQ(inst->GetSingleWordInOperand(1), 4);
|
||||||
|
|
||||||
|
// Check that we are at the end.
|
||||||
|
++inst;
|
||||||
|
EXPECT_EQ(inst, context->annotation_end());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IRContextTest, KillDecorationGroup) {
|
||||||
|
const std::string text = R"(
|
||||||
|
OpCapability Shader
|
||||||
|
%1 = OpExtInstImport "GLSL.std.450"
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint Fragment %2 "main"
|
||||||
|
OpExecutionMode %2 OriginUpperLeft
|
||||||
|
OpSource GLSL 430
|
||||||
|
%3 = OpDecorationGroup
|
||||||
|
OpGroupDecorate %3 %4 %5
|
||||||
|
%6 = OpTypeFloat 32
|
||||||
|
%7 = OpTypePointer Function %6
|
||||||
|
%8 = OpTypeStruct %6
|
||||||
|
%9 = OpTypeVoid
|
||||||
|
%10 = OpTypeFunction %9
|
||||||
|
%2 = OpFunction %9 None %10
|
||||||
|
%11 = OpLabel
|
||||||
|
%4 = OpVariable %7 Function
|
||||||
|
%5 = OpVariable %7 Function
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
std::unique_ptr<IRContext> context =
|
||||||
|
BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
||||||
|
|
||||||
|
// Build the decoration manager.
|
||||||
|
context->get_decoration_mgr();
|
||||||
|
|
||||||
|
// Delete the second variable.
|
||||||
|
context->KillDef(3);
|
||||||
|
|
||||||
|
// Check the OpDecorationGroup Instruction is still there.
|
||||||
|
EXPECT_TRUE(context->annotations().empty());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace opt
|
} // namespace opt
|
||||||
} // namespace spvtools
|
} // namespace spvtools
|
||||||
|
Loading…
Reference in New Issue
Block a user