[SPIR-V] Use a helper class for most if/else branching
Simplifies emission of the blocks themselves (including inserting blocks into the function's block list in the correct order), as well as phi after the branching. Also fixes 64bpp storing with blending in the fragment shader interlock render backend implementation (had a typo that caused the high 32 bits to overwrite the low ones).
This commit is contained in:
@@ -13,6 +13,8 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
|
||||
@@ -101,5 +103,105 @@ spv::Id SpirvBuilder::createTriBuiltinCall(spv::Id result_type,
|
||||
return result;
|
||||
}
|
||||
|
||||
SpirvBuilder::IfBuilder::IfBuilder(spv::Id condition, unsigned int control,
|
||||
SpirvBuilder& builder,
|
||||
unsigned int thenWeight,
|
||||
unsigned int elseWeight)
|
||||
: builder(builder),
|
||||
condition(condition),
|
||||
control(control),
|
||||
thenWeight(thenWeight),
|
||||
elseWeight(elseWeight),
|
||||
function(builder.getBuildPoint()->getParent()) {
|
||||
// Make the blocks, but only put the then-block into the function, the
|
||||
// else-block and merge-block will be added later, in order, after earlier
|
||||
// code is emitted.
|
||||
thenBlock = new spv::Block(builder.getUniqueId(), function);
|
||||
elseBlock = nullptr;
|
||||
mergeBlock = new spv::Block(builder.getUniqueId(), function);
|
||||
|
||||
// Save the current block, so that we can add in the flow control split when
|
||||
// makeEndIf is called.
|
||||
headerBlock = builder.getBuildPoint();
|
||||
|
||||
spv::Id headerBlockId = headerBlock->getId();
|
||||
thenPhiParent = headerBlockId;
|
||||
elsePhiParent = headerBlockId;
|
||||
|
||||
function.addBlock(thenBlock);
|
||||
builder.setBuildPoint(thenBlock);
|
||||
}
|
||||
|
||||
void SpirvBuilder::IfBuilder::makeBeginElse(bool branchToMerge) {
|
||||
#ifndef NDEBUG
|
||||
assert_true(currentBranch == Branch::kThen);
|
||||
#endif
|
||||
|
||||
if (branchToMerge) {
|
||||
// Close out the "then" by having it jump to the mergeBlock.
|
||||
thenPhiParent = builder.getBuildPoint()->getId();
|
||||
builder.createBranch(mergeBlock);
|
||||
}
|
||||
|
||||
// Make the first else block and add it to the function.
|
||||
elseBlock = new spv::Block(builder.getUniqueId(), function);
|
||||
function.addBlock(elseBlock);
|
||||
|
||||
// Start building the else block.
|
||||
builder.setBuildPoint(elseBlock);
|
||||
|
||||
#ifndef NDEBUG
|
||||
currentBranch = Branch::kElse;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SpirvBuilder::IfBuilder::makeEndIf(bool branchToMerge) {
|
||||
#ifndef NDEBUG
|
||||
assert_true(currentBranch == Branch::kThen || currentBranch == Branch::kElse);
|
||||
#endif
|
||||
|
||||
if (branchToMerge) {
|
||||
// Jump to the merge block.
|
||||
(elseBlock ? elsePhiParent : thenPhiParent) =
|
||||
builder.getBuildPoint()->getId();
|
||||
builder.createBranch(mergeBlock);
|
||||
}
|
||||
|
||||
// Go back to the headerBlock and make the flow control split.
|
||||
builder.setBuildPoint(headerBlock);
|
||||
builder.createSelectionMerge(mergeBlock, control);
|
||||
{
|
||||
spv::Block* falseBlock = elseBlock ? elseBlock : mergeBlock;
|
||||
std::unique_ptr<spv::Instruction> branch =
|
||||
std::make_unique<spv::Instruction>(spv::OpBranchConditional);
|
||||
branch->addIdOperand(condition);
|
||||
branch->addIdOperand(thenBlock->getId());
|
||||
branch->addIdOperand(falseBlock->getId());
|
||||
if (thenWeight || elseWeight) {
|
||||
branch->addImmediateOperand(thenWeight);
|
||||
branch->addImmediateOperand(elseWeight);
|
||||
}
|
||||
builder.getBuildPoint()->addInstruction(std::move(branch));
|
||||
thenBlock->addPredecessor(builder.getBuildPoint());
|
||||
falseBlock->addPredecessor(builder.getBuildPoint());
|
||||
}
|
||||
|
||||
// Add the merge block to the function.
|
||||
function.addBlock(mergeBlock);
|
||||
builder.setBuildPoint(mergeBlock);
|
||||
|
||||
#ifndef NDEBUG
|
||||
currentBranch = Branch::kMerge;
|
||||
#endif
|
||||
}
|
||||
|
||||
spv::Id SpirvBuilder::IfBuilder::createMergePhi(spv::Id then_variable,
|
||||
spv::Id else_variable) const {
|
||||
assert_true(builder.getBuildPoint() == mergeBlock);
|
||||
return builder.createQuadOp(spv::OpPhi, builder.getTypeId(then_variable),
|
||||
then_variable, getThenPhiParent(), else_variable,
|
||||
getElsePhiParent());
|
||||
}
|
||||
|
||||
} // namespace gpu
|
||||
} // namespace xe
|
||||
|
||||
Reference in New Issue
Block a user