fix(shader): keep undecoded OpExtInst and runtime logical guards in specialization

This commit is contained in:
hamb3r committed 2026-10-21 18:11:13 +03:00
1 parent d9ce5c9b9b
commit cbdbc601dc
3 files changed
+6 -37

No files matched your search

@@ -322,8 +322,6 @@ void testPrivateCompositeTableLoadFolding() {
const auto input = module.DefineGlobalVariable(typeInputPtr, spv::StorageClassInput);
const auto table = module.DefineInitializedGlobalVariable(typeTablePtr, spv::StorageClassPrivate, initial);
const auto output = module.DefineGlobalVariable(typePrivatePtr, spv::StorageClassPrivate);
const auto glsl = module.Import("GLSL.std.450");
const auto customSet = module.Import("NonSemantic.Test");
const auto mainId = module.AllocateId();
const auto lane = module.AllocateId();
const auto rawCond = module.AllocateId();
@@ -341,11 +339,6 @@ void testPrivateCompositeTableLoadFolding() {
module.AddFunction(accessOp, typePrivatePtr, writePtr, table, zero);
module.AddFunction(spv::OpStore, writePtr, lane);
}
const auto liveGlsl = module.AllocateId();
module.AddFunction(spv::OpExtInst, typeU32, module.AllocateId(), glsl, 37u, lane, zero);
module.AddFunction(spv::OpExtInst, typeU32, liveGlsl, glsl, 37u, lane, one);
module.AddFunction(spv::OpStore, output, liveGlsl);
module.AddFunction(spv::OpExtInst, typeU32, module.AllocateId(), customSet, 1u, lane);
module.AddFunction(spv::OpUGreaterThan, typeBool, rawCond, lane, zero);
module.AddFunction(spv::OpLogicalOr, typeBool, cond, rawCond, falseVal);
module.AddFunction(spv::OpIAdd, typeU32, baseIndex, one, one);
@@ -364,16 +357,12 @@ void testPrivateCompositeTableLoadFolding() {
check(!foldedCounts.contains(spv::OpLogicalOr), "a right-false OpLogicalOr was not simplified");
check(!foldedCounts.contains(spv::OpSelect), "an identical-arm OpSelect was not simplified");
check(foldedCounts.contains(spv::OpLoad) && foldedCounts.at(spv::OpLoad) == 1u, "a constant-index private composite table load was not folded");
check(foldedCounts.contains(spv::OpExtInst) && foldedCounts.at(spv::OpExtInst) == 2u, "an unused GLSL.std.450 OpExtInst was not removed or a live/non-GLSL.std.450 OpExtInst was removed");
bool addedThirty = false;
bool keptCustomExtInst = false;
for (std::size_t cursor = 5; cursor < folded.size(); cursor += folded[cursor] >> 16u) {
if ((folded[cursor] >> 16u) == 0u) break;
if ((folded[cursor] & 0xffffu) == spv::OpIAdd && folded[cursor + 4u] == expectedConstant) addedThirty = true;
if ((folded[cursor] & 0xffffu) == spv::OpExtInst && folded[cursor + 4u] == 1u) keptCustomExtInst = true;
}
check(addedThirty, "a constant-index private composite table load did not fold to its element constant");
check(keptCustomExtInst, "a non-GLSL.std.450 OpExtInst was not preserved");
const auto [dynamic, unusedDynamic] = build(true, false);
static_cast<void>(unusedDynamic);
@@ -446,7 +446,7 @@ std::uint32_t genericFormattedLoad(SpirvValueEmitContext& context, const IrValue
const auto fromMemory = Binary(state, spv::OpUGreaterThanEqual, boolean, selectors[output], constant(4u));
required[component] = Binary(state, spv::OpLogicalOr, boolean, required[component], both(state, fromMemory, equal(state, selected[output], constant(component))));
}
required[component] = both(state, active[component], required[component]);
required[component] = Select(state, boolean, active[component], required[component], ConstantBool(state, false));
const auto componentOffset = field(state, byteOffsets, component * 8u, 8u);
const auto bytes = Select(state, u32, packed, constant(4u), Binary(state, spv::OpShiftRightLogical, u32, bits[component], constant(3u)));
const auto offset = Binary(state, spv::OpIAdd, u32, resource.offset != 0u ? resource.offset : Binary(state, spv::OpIAdd, u32, context.Arg(instruction, 2u), constant(memory.offset)), componentOffset);
@@ -454,16 +454,16 @@ std::uint32_t genericFormattedLoad(SpirvValueEmitContext& context, const IrValue
if (memory.gpuDescriptor) {
const auto u64 = TypeScalarU64(state);
const auto guest = Binary(state, spv::OpIAdd, u64, resource.base, Unary(state, spv::OpUConvert, u64, addresses[component].guest));
const auto overflow = both(state, active[component], Binary(state, spv::OpULessThan, boolean, guest, resource.base));
const auto overflow = Select(state, boolean, active[component], Binary(state, spv::OpULessThan, boolean, guest, resource.base), ConstantBool(state, false));
EmitIfCondition(state, overflow, [&] { RecordBdaFault(state, resource.base, constant(0u), BdaInstructionPc(state, instruction), BdaAbi::FaultReason::Overflow); });
StopBdaInvocationIf(state, overflow);
addresses[component].guest = guest;
}
inBounds = both(state, inBounds, Binary(state, spv::OpLogicalOr, boolean, Unary(state, spv::OpLogicalNot, boolean, required[component]), addresses[component].inBounds));
inBounds = Select(state, boolean, required[component], both(state, inBounds, addresses[component].inBounds), inBounds);
}
std::array<std::uint32_t, 4> values{};
for (std::uint32_t component = 0; component < 4u; ++component) {
values[component] = EmitValueOrZeroIfCondition(state, both(state, inBounds, required[component]), [&] {
values[component] = EmitValueOrZeroIfCondition(state, Select(state, boolean, required[component], inBounds, ConstantBool(state, false)), [&] {
const auto width = Select(state, u32, packed, constant(32u), bits[component]);
const auto dword = equal(state, width, constant(32u));
const auto raw = memory.gpuDescriptor
@@ -100,7 +100,7 @@ private:
std::vector<std::uint8_t> present;
};
bool PureInstruction(const Instruction& instruction, const IdSet& glslExtInstSets = {}) {
bool PureInstruction(const Instruction& instruction) {
switch (Opcode(instruction)) {
case spv::OpVectorExtractDynamic:
case spv::OpVectorInsertDynamic:
@@ -219,8 +219,6 @@ bool PureInstruction(const Instruction& instruction, const IdSet& glslExtInstSet
case spv::OpArrayLength:
case spv::OpPhi:
return true;
case spv::OpExtInst:
return instruction.size() >= 5u && glslExtInstSets.contains(instruction[3]);
case spv::OpLoad:
return instruction.size() == 4u || (instruction.size() == 5u && instruction[4] == spv::MemoryAccessMaskNone);
default:
@@ -233,9 +231,6 @@ bool VisitInputs(const Instruction& instruction, const TVisitor& visit) {
std::size_t first = 3u;
std::size_t end = instruction.size();
switch (Opcode(instruction)) {
case spv::OpExtInst:
first = 5u;
break;
case spv::OpVectorShuffle:
case spv::OpCompositeInsert:
end = 5u;
@@ -583,7 +578,6 @@ public:
values.Reset(bound);
resultTypes.Reset(bound);
vectorTypes.Reset(bound);
glslExtInstSets.Reset(bound);
removed.Reset(bound);
aliases.Reset(bound);
composites.Reset(bound);
@@ -598,7 +592,6 @@ public:
bool hasType = false;
spv::HasResultAndType(op, &hasResult, &hasType);
if (hasResult && hasType) resultTypes.emplace(instruction.at(2), instruction.at(1));
if (op == spv::OpExtInstImport && instruction.size() == 6u && instruction[2] == 0x4c534c47u && instruction[3] == 0x6474732eu && instruction[4] == 0x3035342eu && instruction[5] == 0u) glslExtInstSets.insert(instruction.at(1));
if (op == spv::OpTypeBool) types.emplace(instruction.at(1), ScalarType{1u, true});
if (op == spv::OpTypeInt) types.emplace(instruction.at(1), ScalarType{instruction.at(2), false});
if (op == spv::OpTypeVector) vectorTypes.insert(instruction.at(1));
@@ -680,18 +673,6 @@ private:
return pointer->second < elements.size() ? value(elements[pointer->second]) : std::nullopt;
}
const auto left = value(instruction[3]);
if (op == spv::OpLogicalAnd && instruction.size() == 5u) {
const auto right = value(instruction[4]);
if ((left && *left == 0u) || (right && *right == 0u)) return 0u;
if (left && right) return *left != 0u && *right != 0u;
return std::nullopt;
}
if (op == spv::OpLogicalOr && instruction.size() == 5u) {
const auto right = value(instruction[4]);
if ((left && *left != 0u) || (right && *right != 0u)) return 1u;
if (left && right) return *left != 0u || *right != 0u;
return std::nullopt;
}
if (!left) return std::nullopt;
if (op == spv::OpCopyObject) return left;
if (op == spv::OpLogicalNot) return *left == 0u;
@@ -1128,7 +1109,7 @@ private:
}
continue;
}
if (PureInstruction(instruction, glslExtInstSets)) {
if (PureInstruction(instruction)) {
definitions.emplace(Result(instruction), index);
continue;
}
@@ -1165,7 +1146,6 @@ private:
IdTable<std::uint32_t> values;
IdTable<std::uint32_t> resultTypes;
IdSet vectorTypes;
IdSet glslExtInstSets;
IdSet removed;
IdTable<std::uint32_t> aliases;
IdTable<std::vector<std::uint32_t>> composites;