mirror of
https://github.com/KhronosGroup/glslang
synced 2024-11-09 20:10:06 +00:00
Fix generation of conditionals with a struct result in SPIR-V
It is possible for the SPIR-V code generator to receive a conditional where the two branches have the same shader language level type but different SPIR-V types because of things like offset decorations. This change modifies visitSelection() to handle this case by using either multiTypeStore() or, if that is available, OpCopyLogical. Fixes #3164
This commit is contained in:
parent
f8a2442a16
commit
cdb350b356
@ -3789,10 +3789,11 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang
|
|||||||
// Find a way of executing both sides and selecting the right result.
|
// Find a way of executing both sides and selecting the right result.
|
||||||
const auto executeBothSides = [&]() -> void {
|
const auto executeBothSides = [&]() -> void {
|
||||||
// execute both sides
|
// execute both sides
|
||||||
|
spv::Id resultType = convertGlslangToSpvType(node->getType());
|
||||||
node->getTrueBlock()->traverse(this);
|
node->getTrueBlock()->traverse(this);
|
||||||
spv::Id trueValue = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType());
|
spv::Id trueValue = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType());
|
||||||
node->getFalseBlock()->traverse(this);
|
node->getFalseBlock()->traverse(this);
|
||||||
spv::Id falseValue = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType());
|
spv::Id falseValue = accessChainLoad(node->getFalseBlock()->getAsTyped()->getType());
|
||||||
|
|
||||||
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
||||||
|
|
||||||
@ -3801,8 +3802,8 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// emit code to select between trueValue and falseValue
|
// emit code to select between trueValue and falseValue
|
||||||
|
// see if OpSelect can handle the result type, and that the SPIR-V types
|
||||||
// see if OpSelect can handle it
|
// of the inputs match the result type.
|
||||||
if (isOpSelectable()) {
|
if (isOpSelectable()) {
|
||||||
// Emit OpSelect for this selection.
|
// Emit OpSelect for this selection.
|
||||||
|
|
||||||
@ -3814,10 +3815,18 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang
|
|||||||
builder.getNumComponents(trueValue)));
|
builder.getNumComponents(trueValue)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the types do not match, it is because of mismatched decorations on aggregates.
|
||||||
|
// Since isOpSelectable only lets us get here for SPIR-V >= 1.4, we can use OpCopyObject
|
||||||
|
// to get matching types.
|
||||||
|
if (builder.getTypeId(trueValue) != resultType) {
|
||||||
|
trueValue = builder.createUnaryOp(spv::OpCopyLogical, resultType, trueValue);
|
||||||
|
}
|
||||||
|
if (builder.getTypeId(falseValue) != resultType) {
|
||||||
|
falseValue = builder.createUnaryOp(spv::OpCopyLogical, resultType, falseValue);
|
||||||
|
}
|
||||||
|
|
||||||
// OpSelect
|
// OpSelect
|
||||||
result = builder.createTriOp(spv::OpSelect,
|
result = builder.createTriOp(spv::OpSelect, resultType, condition, trueValue, falseValue);
|
||||||
convertGlslangToSpvType(node->getType()), condition,
|
|
||||||
trueValue, falseValue);
|
|
||||||
|
|
||||||
builder.clearAccessChain();
|
builder.clearAccessChain();
|
||||||
builder.setAccessChainRValue(result);
|
builder.setAccessChainRValue(result);
|
||||||
@ -3825,7 +3834,7 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang
|
|||||||
// We need control flow to select the result.
|
// We need control flow to select the result.
|
||||||
// TODO: Once SPIR-V OpSelect allows arbitrary types, eliminate this path.
|
// TODO: Once SPIR-V OpSelect allows arbitrary types, eliminate this path.
|
||||||
result = builder.createVariable(TranslatePrecisionDecoration(node->getType()),
|
result = builder.createVariable(TranslatePrecisionDecoration(node->getType()),
|
||||||
spv::StorageClassFunction, convertGlslangToSpvType(node->getType()));
|
spv::StorageClassFunction, resultType);
|
||||||
|
|
||||||
// Selection control:
|
// Selection control:
|
||||||
const spv::SelectionControlMask control = TranslateSelectionControl(*node);
|
const spv::SelectionControlMask control = TranslateSelectionControl(*node);
|
||||||
@ -3834,10 +3843,15 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang
|
|||||||
spv::Builder::If ifBuilder(condition, control, builder);
|
spv::Builder::If ifBuilder(condition, control, builder);
|
||||||
|
|
||||||
// emit the "then" statement
|
// emit the "then" statement
|
||||||
builder.createStore(trueValue, result);
|
builder.clearAccessChain();
|
||||||
|
builder.setAccessChainLValue(result);
|
||||||
|
multiTypeStore(node->getType(), trueValue);
|
||||||
|
|
||||||
ifBuilder.makeBeginElse();
|
ifBuilder.makeBeginElse();
|
||||||
// emit the "else" statement
|
// emit the "else" statement
|
||||||
builder.createStore(falseValue, result);
|
builder.clearAccessChain();
|
||||||
|
builder.setAccessChainLValue(result);
|
||||||
|
multiTypeStore(node->getType(), falseValue);
|
||||||
|
|
||||||
// finish off the control flow
|
// finish off the control flow
|
||||||
ifBuilder.makeEndIf();
|
ifBuilder.makeEndIf();
|
||||||
@ -3864,16 +3878,26 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang
|
|||||||
// emit the "then" statement
|
// emit the "then" statement
|
||||||
if (node->getTrueBlock() != nullptr) {
|
if (node->getTrueBlock() != nullptr) {
|
||||||
node->getTrueBlock()->traverse(this);
|
node->getTrueBlock()->traverse(this);
|
||||||
if (result != spv::NoResult)
|
if (result != spv::NoResult) {
|
||||||
builder.createStore(accessChainLoad(node->getTrueBlock()->getAsTyped()->getType()), result);
|
spv::Id load = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType());
|
||||||
|
|
||||||
|
builder.clearAccessChain();
|
||||||
|
builder.setAccessChainLValue(result);
|
||||||
|
multiTypeStore(node->getType(), load);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->getFalseBlock() != nullptr) {
|
if (node->getFalseBlock() != nullptr) {
|
||||||
ifBuilder.makeBeginElse();
|
ifBuilder.makeBeginElse();
|
||||||
// emit the "else" statement
|
// emit the "else" statement
|
||||||
node->getFalseBlock()->traverse(this);
|
node->getFalseBlock()->traverse(this);
|
||||||
if (result != spv::NoResult)
|
if (result != spv::NoResult) {
|
||||||
builder.createStore(accessChainLoad(node->getFalseBlock()->getAsTyped()->getType()), result);
|
spv::Id load = accessChainLoad(node->getFalseBlock()->getAsTyped()->getType());
|
||||||
|
|
||||||
|
builder.clearAccessChain();
|
||||||
|
builder.setAccessChainLValue(result);
|
||||||
|
multiTypeStore(node->getType(), load);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// finish off the control flow
|
// finish off the control flow
|
||||||
|
Loading…
Reference in New Issue
Block a user