[SPIR-V] Main program counter switch
This commit is contained in:
parent
1de144938c
commit
7846245b66
|
@ -29,7 +29,8 @@ void SpirvShaderTranslator::Reset() {
|
||||||
|
|
||||||
builder_.reset();
|
builder_.reset();
|
||||||
|
|
||||||
// main_switch_cases_.reset();
|
main_switch_op_.reset();
|
||||||
|
main_switch_next_pc_phi_operands_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpirvShaderTranslator::StartTranslation() {
|
void SpirvShaderTranslator::StartTranslation() {
|
||||||
|
@ -117,7 +118,6 @@ void SpirvShaderTranslator::StartTranslation() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the main loop.
|
// Open the main loop.
|
||||||
|
|
||||||
spv::Block* main_loop_pre_header = builder_->getBuildPoint();
|
spv::Block* main_loop_pre_header = builder_->getBuildPoint();
|
||||||
main_loop_header_ = &builder_->makeNewBlock();
|
main_loop_header_ = &builder_->makeNewBlock();
|
||||||
spv::Block& main_loop_body = builder_->makeNewBlock();
|
spv::Block& main_loop_body = builder_->makeNewBlock();
|
||||||
|
@ -130,18 +130,25 @@ void SpirvShaderTranslator::StartTranslation() {
|
||||||
main_loop_merge_ = new spv::Block(builder_->getUniqueId(), *function_main_);
|
main_loop_merge_ = new spv::Block(builder_->getUniqueId(), *function_main_);
|
||||||
builder_->createBranch(main_loop_header_);
|
builder_->createBranch(main_loop_header_);
|
||||||
|
|
||||||
|
// If no jumps, don't create a switch, but still create a loop so exece can
|
||||||
|
// break.
|
||||||
|
bool has_main_switch = !label_addresses().empty();
|
||||||
|
|
||||||
// Main loop header - based on whether it's the first iteration (entered from
|
// Main loop header - based on whether it's the first iteration (entered from
|
||||||
// the function or from the continuation), choose the program counter.
|
// the function or from the continuation), choose the program counter.
|
||||||
builder_->setBuildPoint(main_loop_header_);
|
builder_->setBuildPoint(main_loop_header_);
|
||||||
id_vector_temp_.clear();
|
spv::Id main_loop_pc_current = 0;
|
||||||
id_vector_temp_.reserve(4);
|
if (has_main_switch) {
|
||||||
id_vector_temp_.push_back(const_int_0_);
|
id_vector_temp_.clear();
|
||||||
id_vector_temp_.push_back(main_loop_pre_header->getId());
|
id_vector_temp_.reserve(4);
|
||||||
main_loop_pc_next_ = builder_->getUniqueId();
|
id_vector_temp_.push_back(const_int_0_);
|
||||||
id_vector_temp_.push_back(main_loop_pc_next_);
|
id_vector_temp_.push_back(main_loop_pre_header->getId());
|
||||||
id_vector_temp_.push_back(main_loop_continue_->getId());
|
main_loop_pc_next_ = builder_->getUniqueId();
|
||||||
spv::Id main_loop_pc_current =
|
id_vector_temp_.push_back(main_loop_pc_next_);
|
||||||
builder_->createOp(spv::OpPhi, type_int_, id_vector_temp_);
|
id_vector_temp_.push_back(main_loop_continue_->getId());
|
||||||
|
main_loop_pc_current =
|
||||||
|
builder_->createOp(spv::OpPhi, type_int_, id_vector_temp_);
|
||||||
|
}
|
||||||
uint_vector_temp_.clear();
|
uint_vector_temp_.clear();
|
||||||
builder_->createLoopMerge(main_loop_merge_, main_loop_continue_,
|
builder_->createLoopMerge(main_loop_merge_, main_loop_continue_,
|
||||||
spv::LoopControlDontUnrollMask, uint_vector_temp_);
|
spv::LoopControlDontUnrollMask, uint_vector_temp_);
|
||||||
|
@ -149,29 +156,86 @@ void SpirvShaderTranslator::StartTranslation() {
|
||||||
|
|
||||||
// Main loop body.
|
// Main loop body.
|
||||||
builder_->setBuildPoint(&main_loop_body);
|
builder_->setBuildPoint(&main_loop_body);
|
||||||
// TODO(Triang3l): Create the switch, add the block for the case 0 and set the
|
if (has_main_switch) {
|
||||||
// build point to it.
|
// Create the program counter switch with cases for every label and for
|
||||||
|
// label 0.
|
||||||
|
main_switch_header_ = builder_->getBuildPoint();
|
||||||
|
main_switch_merge_ =
|
||||||
|
new spv::Block(builder_->getUniqueId(), *function_main_);
|
||||||
|
{
|
||||||
|
std::unique_ptr<spv::Instruction> main_switch_selection_merge_op =
|
||||||
|
std::make_unique<spv::Instruction>(spv::OpSelectionMerge);
|
||||||
|
main_switch_selection_merge_op->addIdOperand(main_switch_merge_->getId());
|
||||||
|
main_switch_selection_merge_op->addImmediateOperand(
|
||||||
|
spv::SelectionControlDontFlattenMask);
|
||||||
|
builder_->getBuildPoint()->addInstruction(
|
||||||
|
std::move(main_switch_selection_merge_op));
|
||||||
|
}
|
||||||
|
main_switch_op_ = std::make_unique<spv::Instruction>(spv::OpSwitch);
|
||||||
|
main_switch_op_->addIdOperand(main_loop_pc_current);
|
||||||
|
main_switch_op_->addIdOperand(main_switch_merge_->getId());
|
||||||
|
// The default case (the merge here) must have the header as a predecessor.
|
||||||
|
main_switch_merge_->addPredecessor(main_switch_header_);
|
||||||
|
// The instruction will be inserted later, when all cases are filled.
|
||||||
|
// Insert and enter case 0.
|
||||||
|
spv::Block* main_switch_case_0_block =
|
||||||
|
new spv::Block(builder_->getUniqueId(), *function_main_);
|
||||||
|
main_switch_op_->addImmediateOperand(0);
|
||||||
|
main_switch_op_->addIdOperand(main_switch_case_0_block->getId());
|
||||||
|
// Every switch case must have the OpSelectionMerge/OpSwitch block as a
|
||||||
|
// predecessor.
|
||||||
|
main_switch_case_0_block->addPredecessor(main_switch_header_);
|
||||||
|
function_main_->addBlock(main_switch_case_0_block);
|
||||||
|
builder_->setBuildPoint(main_switch_case_0_block);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> SpirvShaderTranslator::CompleteTranslation() {
|
std::vector<uint8_t> SpirvShaderTranslator::CompleteTranslation() {
|
||||||
// Close the main loop.
|
bool has_main_switch = !label_addresses().empty();
|
||||||
// Break from the body after falling through the end or breaking.
|
// After the final exec (if it happened to be not exece, which would already
|
||||||
builder_->createBranch(main_loop_merge_);
|
// have a break branch), break from the switch if it exists, or from the
|
||||||
|
// loop it doesn't.
|
||||||
|
if (!builder_->getBuildPoint()->isTerminated()) {
|
||||||
|
builder_->createBranch(has_main_switch ? main_switch_merge_
|
||||||
|
: main_loop_merge_);
|
||||||
|
}
|
||||||
|
if (has_main_switch) {
|
||||||
|
// Insert the switch instruction with all cases added as operands.
|
||||||
|
builder_->setBuildPoint(main_switch_header_);
|
||||||
|
builder_->getBuildPoint()->addInstruction(std::move(main_switch_op_));
|
||||||
|
// Build the main switch merge, breaking out of the loop after falling
|
||||||
|
// through the end or breaking from exece (only continuing if a jump - from
|
||||||
|
// a guest loop or from jmp/call - was made).
|
||||||
|
function_main_->addBlock(main_switch_merge_);
|
||||||
|
builder_->setBuildPoint(main_switch_merge_);
|
||||||
|
builder_->createBranch(main_loop_merge_);
|
||||||
|
}
|
||||||
|
|
||||||
// Main loop continuation - choose the program counter based on the path
|
// Main loop continuation - choose the program counter based on the path
|
||||||
// taken (-1 if not from a jump as a safe fallback, which would result in not
|
// taken (-1 if not from a jump as a safe fallback, which would result in not
|
||||||
// hitting any switch case and reaching the final break in the body).
|
// hitting any switch case and reaching the final break in the body).
|
||||||
function_main_->addBlock(main_loop_continue_);
|
function_main_->addBlock(main_loop_continue_);
|
||||||
builder_->setBuildPoint(main_loop_continue_);
|
builder_->setBuildPoint(main_loop_continue_);
|
||||||
{
|
if (has_main_switch) {
|
||||||
|
// If labels were added, but not jumps (for example, due to the call
|
||||||
|
// instruction not being implemented as of October 18, 2020), send an
|
||||||
|
// impossible program counter value (-1) to the OpPhi at the next iteration.
|
||||||
|
if (main_switch_next_pc_phi_operands_.empty()) {
|
||||||
|
main_switch_next_pc_phi_operands_.push_back(
|
||||||
|
builder_->makeIntConstant(-1));
|
||||||
|
}
|
||||||
std::unique_ptr<spv::Instruction> main_loop_pc_next_op =
|
std::unique_ptr<spv::Instruction> main_loop_pc_next_op =
|
||||||
std::make_unique<spv::Instruction>(main_loop_pc_next_, type_int_,
|
std::make_unique<spv::Instruction>(
|
||||||
spv::OpCopyObject);
|
main_loop_pc_next_, type_int_,
|
||||||
// TODO(Triang3l): Phi between the continues in the switch cases and the
|
main_switch_next_pc_phi_operands_.size() >= 2 ? spv::OpPhi
|
||||||
// switch merge block.
|
: spv::OpCopyObject);
|
||||||
main_loop_pc_next_op->addIdOperand(builder_->makeIntConstant(-1));
|
for (spv::Id operand : main_switch_next_pc_phi_operands_) {
|
||||||
|
main_loop_pc_next_op->addIdOperand(operand);
|
||||||
|
}
|
||||||
builder_->getBuildPoint()->addInstruction(std::move(main_loop_pc_next_op));
|
builder_->getBuildPoint()->addInstruction(std::move(main_loop_pc_next_op));
|
||||||
}
|
}
|
||||||
builder_->createBranch(main_loop_header_);
|
builder_->createBranch(main_loop_header_);
|
||||||
|
|
||||||
// Add the main loop merge block and go back to the function.
|
// Add the main loop merge block and go back to the function.
|
||||||
function_main_->addBlock(main_loop_merge_);
|
function_main_->addBlock(main_loop_merge_);
|
||||||
builder_->setBuildPoint(main_loop_merge_);
|
builder_->setBuildPoint(main_loop_merge_);
|
||||||
|
@ -214,6 +278,27 @@ std::vector<uint8_t> SpirvShaderTranslator::CompleteTranslation() {
|
||||||
return module_bytes;
|
return module_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpirvShaderTranslator::ProcessLabel(uint32_t cf_index) {
|
||||||
|
if (cf_index == 0) {
|
||||||
|
// 0 already added in the beginning.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
spv::Function& function = builder_->getBuildPoint()->getParent();
|
||||||
|
// Create the next switch case and fallthrough to it.
|
||||||
|
spv::Block* new_case = new spv::Block(builder_->getUniqueId(), function);
|
||||||
|
main_switch_op_->addImmediateOperand(cf_index);
|
||||||
|
main_switch_op_->addIdOperand(new_case->getId());
|
||||||
|
// Every switch case must have the OpSelectionMerge/OpSwitch block as a
|
||||||
|
// predecessor.
|
||||||
|
new_case->addPredecessor(main_switch_header_);
|
||||||
|
// The previous block may have already been terminated if was exece.
|
||||||
|
if (!builder_->getBuildPoint()->isTerminated()) {
|
||||||
|
builder_->createBranch(new_case);
|
||||||
|
}
|
||||||
|
function.addBlock(new_case);
|
||||||
|
builder_->setBuildPoint(new_case);
|
||||||
|
}
|
||||||
|
|
||||||
void SpirvShaderTranslator::StartVertexOrTessEvalShaderBeforeMain() {
|
void SpirvShaderTranslator::StartVertexOrTessEvalShaderBeforeMain() {
|
||||||
// Create the inputs.
|
// Create the inputs.
|
||||||
if (IsSpirvTessEvalShader()) {
|
if (IsSpirvTessEvalShader()) {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "third_party/glslang/SPIRV/SpvBuilder.h"
|
#include "third_party/glslang/SPIRV/SpvBuilder.h"
|
||||||
|
@ -32,6 +33,8 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
||||||
|
|
||||||
std::vector<uint8_t> CompleteTranslation() override;
|
std::vector<uint8_t> CompleteTranslation() override;
|
||||||
|
|
||||||
|
void ProcessLabel(uint32_t cf_index) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// TODO(Triang3l): Depth-only pixel shader.
|
// TODO(Triang3l): Depth-only pixel shader.
|
||||||
bool IsSpirvVertexOrTessEvalShader() const { return is_vertex_shader(); }
|
bool IsSpirvVertexOrTessEvalShader() const { return is_vertex_shader(); }
|
||||||
|
@ -104,6 +107,10 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
||||||
spv::Block* main_loop_continue_;
|
spv::Block* main_loop_continue_;
|
||||||
spv::Block* main_loop_merge_;
|
spv::Block* main_loop_merge_;
|
||||||
spv::Id main_loop_pc_next_;
|
spv::Id main_loop_pc_next_;
|
||||||
|
spv::Block* main_switch_header_;
|
||||||
|
std::unique_ptr<spv::Instruction> main_switch_op_;
|
||||||
|
spv::Block* main_switch_merge_;
|
||||||
|
std::vector<spv::Id> main_switch_next_pc_phi_operands_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gpu
|
} // namespace gpu
|
||||||
|
|
Loading…
Reference in New Issue