Skip to content

Commit 8d3ee2e

Browse files
authored
spirv-opt: Fix OpCompositeExtract relaxation with struct operands (KhronosGroup#5536)
1 parent 61c51d4 commit 8d3ee2e

File tree

2 files changed

+91
-2
lines changed

2 files changed

+91
-2
lines changed

source/opt/convert_to_half_pass.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,19 @@ bool ConvertToHalfPass::RemoveRelaxedDecoration(uint32_t id) {
171171

172172
bool ConvertToHalfPass::GenHalfArith(Instruction* inst) {
173173
bool modified = false;
174+
// If this is a OpCompositeExtract instruction and has a struct operand, we
175+
// should not relax this instruction. Doing so could cause a mismatch between
176+
// the result type and the struct member type.
177+
bool hasStructOperand = false;
178+
if (inst->opcode() == spv::Op::OpCompositeExtract) {
179+
inst->ForEachInId([&hasStructOperand, this](uint32_t* idp) {
180+
Instruction* op_inst = get_def_use_mgr()->GetDef(*idp);
181+
if (IsStruct(op_inst)) hasStructOperand = true;
182+
});
183+
if (hasStructOperand) {
184+
return false;
185+
}
186+
}
174187
// Convert all float32 based operands to float16 equivalent and change
175188
// instruction type to float16 equivalent.
176189
inst->ForEachInId([&inst, &modified, this](uint32_t* idp) {
@@ -303,12 +316,19 @@ bool ConvertToHalfPass::CloseRelaxInst(Instruction* inst) {
303316
if (closure_ops_.count(inst->opcode()) == 0) return false;
304317
// Can relax if all float operands are relaxed
305318
bool relax = true;
306-
inst->ForEachInId([&relax, this](uint32_t* idp) {
319+
bool hasStructOperand = false;
320+
inst->ForEachInId([&relax, &hasStructOperand, this](uint32_t* idp) {
307321
Instruction* op_inst = get_def_use_mgr()->GetDef(*idp);
308-
if (IsStruct(op_inst)) relax = false;
322+
if (IsStruct(op_inst)) hasStructOperand = true;
309323
if (!IsFloat(op_inst, 32)) return;
310324
if (!IsRelaxed(*idp)) relax = false;
311325
});
326+
// If the instruction has a struct operand, we should not relax it, even if
327+
// all its uses are relaxed. Doing so could cause a mismatch between the
328+
// result type and the struct member type.
329+
if (hasStructOperand) {
330+
return false;
331+
}
312332
if (relax) {
313333
AddRelaxed(inst->result_id());
314334
return true;

test/opt/convert_relaxed_to_half_test.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1713,6 +1713,75 @@ TEST_F(ConvertToHalfTest, PreserveImageOperandPrecision) {
17131713
SinglePassRunAndMatch<ConvertToHalfPass>(test, true);
17141714
}
17151715

1716+
TEST_F(ConvertToHalfTest, DontRelaxDecoratedOpCompositeExtract) {
1717+
// This test checks that a OpCompositeExtract with a Struct operand won't be
1718+
// relaxed, even if it is explicitly decorated with RelaxedPrecision.
1719+
const std::string test =
1720+
R"(OpCapability Shader
1721+
OpMemoryModel Logical GLSL450
1722+
OpEntryPoint Fragment %1 "main"
1723+
OpExecutionMode %1 OriginUpperLeft
1724+
OpDecorate %9 RelaxedPrecision
1725+
%void = OpTypeVoid
1726+
%3 = OpTypeFunction %void
1727+
%float = OpTypeFloat 32
1728+
%v4float = OpTypeVector %float 4
1729+
%_struct_6 = OpTypeStruct %v4float
1730+
%7 = OpUndef %_struct_6
1731+
%1 = OpFunction %void None %3
1732+
%8 = OpLabel
1733+
%9 = OpCompositeExtract %float %7 0 3
1734+
OpReturn
1735+
OpFunctionEnd
1736+
)";
1737+
1738+
const std::string expected =
1739+
R"(OpCapability Shader
1740+
OpMemoryModel Logical GLSL450
1741+
OpEntryPoint Fragment %1 "main"
1742+
OpExecutionMode %1 OriginUpperLeft
1743+
%void = OpTypeVoid
1744+
%3 = OpTypeFunction %void
1745+
%float = OpTypeFloat 32
1746+
%v4float = OpTypeVector %float 4
1747+
%_struct_6 = OpTypeStruct %v4float
1748+
%7 = OpUndef %_struct_6
1749+
%1 = OpFunction %void None %3
1750+
%8 = OpLabel
1751+
%9 = OpCompositeExtract %float %7 0 3
1752+
OpReturn
1753+
OpFunctionEnd
1754+
)";
1755+
1756+
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1757+
SinglePassRunAndCheck<ConvertToHalfPass>(test, expected, true);
1758+
}
1759+
1760+
TEST_F(ConvertToHalfTest, DontRelaxOpCompositeExtract) {
1761+
// This test checks that a OpCompositeExtract with a Struct operand won't be
1762+
// relaxed, even if its result has no uses.
1763+
const std::string test =
1764+
R"(OpCapability Shader
1765+
OpMemoryModel Logical GLSL450
1766+
OpEntryPoint Fragment %1 "main"
1767+
OpExecutionMode %1 OriginUpperLeft
1768+
%void = OpTypeVoid
1769+
%3 = OpTypeFunction %void
1770+
%float = OpTypeFloat 32
1771+
%v4float = OpTypeVector %float 4
1772+
%_struct_6 = OpTypeStruct %v4float
1773+
%7 = OpUndef %_struct_6
1774+
%1 = OpFunction %void None %3
1775+
%8 = OpLabel
1776+
%9 = OpCompositeExtract %float %7 0 3
1777+
OpReturn
1778+
OpFunctionEnd
1779+
)";
1780+
1781+
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1782+
SinglePassRunAndCheck<ConvertToHalfPass>(test, test, true);
1783+
}
1784+
17161785
} // namespace
17171786
} // namespace opt
17181787
} // namespace spvtools

0 commit comments

Comments
 (0)