Basic control flow skeleton and jumps implemented.

A-train's trees draw right now!
Helps a bit with #473 but still need to implement loops.
This commit is contained in:
Ben Vanik 2015-12-06 11:44:22 -08:00
parent 934b0d5bbc
commit 280c0b35f6
5 changed files with 98 additions and 13 deletions

View File

@ -287,23 +287,50 @@ void main() {
EmitSource(" vec4 src0;\n");
EmitSource(" vec4 src1;\n");
EmitSource(" vec4 src2;\n");
// Master loop and switch for flow control.
EmitSourceDepth("int pc = 0;\n");
EmitSourceDepth("while (pc != 0xFFFF) {\n");
Indent();
EmitSourceDepth("switch (pc) {\n");
}
std::vector<uint8_t> GlslShaderTranslator::CompleteTranslation() {
// End of master switch.
EmitSourceDepth("default: pc = 0xFFFF; break;\n");
EmitSourceDepth("}; // switch\n");
Unindent();
EmitSourceDepth("} // while\n");
// End of process*() function.
EmitSource("}\n");
return source_.ToBytes();
}
void GlslShaderTranslator::ProcessLabel(uint32_t cf_index) {
EmitUnimplementedTranslationError();
}
void GlslShaderTranslator::ProcessLabel(uint32_t cf_index) {}
void GlslShaderTranslator::ProcessControlFlowNopInstruction() {
EmitSource("// cnop\n");
}
void GlslShaderTranslator::ProcessControlFlowInstructionBegin(
uint32_t cf_index) {
cf_wrote_pc_ = false;
EmitSourceDepth("case 0x%X: // L%d\n", cf_index, cf_index);
Indent();
}
void GlslShaderTranslator::ProcessControlFlowInstructionEnd(uint32_t cf_index) {
if (!cf_wrote_pc_) {
uint32_t next_index = cf_index + 1;
EmitSourceDepth("pc = 0x%X; // Fallthrough to L%d\n", next_index,
next_index);
}
EmitSourceDepth("break;\n");
Unindent();
}
void GlslShaderTranslator::ProcessExecInstructionBegin(
const ParsedExecInstruction& instr) {
EmitSource("// ");
@ -330,6 +357,10 @@ void GlslShaderTranslator::ProcessExecInstructionEnd(
const ParsedExecInstruction& instr) {
Unindent();
EmitSourceDepth("}\n");
if (instr.is_end) {
EmitSourceDepth("pc = 0xFFFF;\n");
cf_wrote_pc_ = true;
}
}
void GlslShaderTranslator::ProcessLoopStartInstruction(
@ -369,7 +400,39 @@ void GlslShaderTranslator::ProcessJumpInstruction(
EmitSource("// ");
instr.Disassemble(&source_);
EmitUnimplementedTranslationError();
bool needs_fallthrough = false;
switch (instr.type) {
case ParsedJumpInstruction::Type::kUnconditional:
EmitSourceDepth("{\n");
break;
case ParsedJumpInstruction::Type::kConditional:
EmitSourceDepth("if ((state.bool_consts[%d] & (1 << %d)) == %c) {\n",
instr.bool_constant_index / 32,
instr.bool_constant_index % 32,
instr.condition ? '1' : '0');
needs_fallthrough = true;
break;
case ParsedJumpInstruction::Type::kPredicated:
EmitSourceDepth("if (%cp0) {\n", instr.condition ? ' ' : '!');
needs_fallthrough = true;
break;
}
Indent();
EmitSourceDepth("pc = 0x%X; // L%d\n", instr.target_address,
instr.target_address);
cf_wrote_pc_ = true;
Unindent();
if (needs_fallthrough) {
uint32_t next_address = instr.dword_index + 1;
EmitSourceDepth("} else {\n");
EmitSourceDepth(" pc = 0x%X; // Fallthrough to L%d\n", next_address,
next_address);
EmitSourceDepth("}\n");
} else {
EmitSourceDepth("}\n");
}
}
void GlslShaderTranslator::ProcessAllocInstruction(

View File

@ -40,6 +40,8 @@ class GlslShaderTranslator : public ShaderTranslator {
void ProcessLabel(uint32_t cf_index) override;
void ProcessControlFlowNopInstruction() override;
void ProcessControlFlowInstructionBegin(uint32_t cf_index) override;
void ProcessControlFlowInstructionEnd(uint32_t cf_index) override;
void ProcessExecInstructionBegin(const ParsedExecInstruction& instr) override;
void ProcessExecInstructionEnd(const ParsedExecInstruction& instr) override;
void ProcessLoopStartInstruction(
@ -70,6 +72,7 @@ class GlslShaderTranslator : public ShaderTranslator {
StringBuffer source_;
int depth_ = 0;
char depth_prefix_[16] = {0};
bool cf_wrote_pc_ = false;
void ProcessVectorAluInstruction(const ParsedAluInstruction& instr);
void ProcessScalarAluInstruction(const ParsedAluInstruction& instr);

View File

@ -195,6 +195,8 @@ struct ParsedExecInstruction {
// Required condition value of the comparision (true or false).
bool condition = false;
// Whether this exec ends the shader.
bool is_end = false;
// Whether to reset the current predicate.
bool clean = true;
// ?

View File

@ -303,22 +303,28 @@ bool ShaderTranslator::TranslateBlocks() {
ControlFlowInstruction cf_b;
UnpackControlFlowInstructions(ucode_dwords_ + i, &cf_a, &cf_b);
cf_index_ = cf_index;
MarkUcodeInstruction(i);
if (label_addresses.count(cf_index)) {
AppendUcodeDisasmFormat(" label L%u\n", cf_index);
ProcessLabel(cf_index);
}
AppendUcodeDisasmFormat("/* %4u.0 */ ", cf_index / 2);
ProcessControlFlowInstructionBegin(cf_index);
TranslateControlFlowInstruction(cf_a);
ProcessControlFlowInstructionEnd(cf_index);
++cf_index;
cf_index_ = cf_index;
MarkUcodeInstruction(i);
if (label_addresses.count(cf_index)) {
AppendUcodeDisasmFormat(" label L%u\n", cf_index);
ProcessLabel(cf_index);
}
AppendUcodeDisasmFormat("/* %4u.1 */ ", cf_index / 2);
ProcessControlFlowInstructionBegin(cf_index);
TranslateControlFlowInstruction(cf_b);
ProcessControlFlowInstructionEnd(cf_index);
++cf_index;
}
@ -399,12 +405,13 @@ void ShaderTranslator::TranslateControlFlowNop(
void ShaderTranslator::TranslateControlFlowExec(
const ControlFlowExecInstruction& cf) {
ParsedExecInstruction i;
i.dword_index = 0;
i.dword_index = cf_index_;
i.opcode = cf.opcode();
i.opcode_name = cf.opcode() == ControlFlowOpcode::kExecEnd ? "exece" : "exec";
i.instruction_address = cf.address();
i.instruction_count = cf.count();
i.type = ParsedExecInstruction::Type::kUnconditional;
i.is_end = cf.opcode() == ControlFlowOpcode::kExecEnd;
i.clean = cf.clean();
i.is_yield = cf.is_yield();
i.sequence = cf.sequence();
@ -415,13 +422,14 @@ void ShaderTranslator::TranslateControlFlowExec(
void ShaderTranslator::TranslateControlFlowCondExec(
const ControlFlowCondExecInstruction& cf) {
ParsedExecInstruction i;
i.dword_index = 0;
i.dword_index = cf_index_;
i.opcode = cf.opcode();
i.opcode_name = "cexec";
switch (cf.opcode()) {
case ControlFlowOpcode::kCondExecEnd:
case ControlFlowOpcode::kCondExecPredCleanEnd:
i.opcode_name = "cexece";
i.is_end = true;
break;
}
i.instruction_address = cf.address();
@ -444,7 +452,7 @@ void ShaderTranslator::TranslateControlFlowCondExec(
void ShaderTranslator::TranslateControlFlowCondExecPred(
const ControlFlowCondExecPredInstruction& cf) {
ParsedExecInstruction i;
i.dword_index = 0;
i.dword_index = cf_index_;
i.opcode = cf.opcode();
i.opcode_name =
cf.opcode() == ControlFlowOpcode::kCondExecPredEnd ? "exece" : "exec";
@ -452,6 +460,7 @@ void ShaderTranslator::TranslateControlFlowCondExecPred(
i.instruction_count = cf.count();
i.type = ParsedExecInstruction::Type::kPredicated;
i.condition = cf.condition();
i.is_end = cf.opcode() == ControlFlowOpcode::kCondExecPredEnd;
i.clean = cf.clean();
i.is_yield = cf.is_yield();
i.sequence = cf.sequence();
@ -462,7 +471,7 @@ void ShaderTranslator::TranslateControlFlowCondExecPred(
void ShaderTranslator::TranslateControlFlowLoopStart(
const ControlFlowLoopStartInstruction& cf) {
ParsedLoopStartInstruction i;
i.dword_index = 0;
i.dword_index = cf_index_;
i.loop_constant_index = cf.loop_id();
i.is_repeat = cf.is_repeat();
i.loop_skip_address = cf.address();
@ -475,7 +484,7 @@ void ShaderTranslator::TranslateControlFlowLoopStart(
void ShaderTranslator::TranslateControlFlowLoopEnd(
const ControlFlowLoopEndInstruction& cf) {
ParsedLoopEndInstruction i;
i.dword_index = 0;
i.dword_index = cf_index_;
i.is_predicated_break = cf.is_predicated_break();
i.predicate_condition = cf.condition();
i.loop_constant_index = cf.loop_id();
@ -489,7 +498,7 @@ void ShaderTranslator::TranslateControlFlowLoopEnd(
void ShaderTranslator::TranslateControlFlowCondCall(
const ControlFlowCondCallInstruction& cf) {
ParsedCallInstruction i;
i.dword_index = 0;
i.dword_index = cf_index_;
i.target_address = cf.address();
if (cf.is_unconditional()) {
i.type = ParsedCallInstruction::Type::kUnconditional;
@ -510,7 +519,7 @@ void ShaderTranslator::TranslateControlFlowCondCall(
void ShaderTranslator::TranslateControlFlowReturn(
const ControlFlowReturnInstruction& cf) {
ParsedReturnInstruction i;
i.dword_index = 0;
i.dword_index = cf_index_;
i.Disassemble(&ucode_disasm_buffer_);
@ -520,7 +529,7 @@ void ShaderTranslator::TranslateControlFlowReturn(
void ShaderTranslator::TranslateControlFlowCondJmp(
const ControlFlowCondJmpInstruction& cf) {
ParsedJumpInstruction i;
i.dword_index = 0;
i.dword_index = cf_index_;
i.target_address = cf.address();
if (cf.is_unconditional()) {
i.type = ParsedJumpInstruction::Type::kUnconditional;
@ -541,7 +550,7 @@ void ShaderTranslator::TranslateControlFlowCondJmp(
void ShaderTranslator::TranslateControlFlowAlloc(
const ControlFlowAllocInstruction& cf) {
ParsedAllocInstruction i;
i.dword_index = 0;
i.dword_index = cf_index_;
i.type = cf.alloc_type();
i.count = cf.size();
i.is_vertex_shader = is_vertex_shader();

View File

@ -74,6 +74,11 @@ class ShaderTranslator {
// Handles translation for control flow nop instructions.
virtual void ProcessControlFlowNopInstruction() {}
// Handles the start of a control flow instruction at the given address.
virtual void ProcessControlFlowInstructionBegin(uint32_t cf_index) {}
// Handles the end of a control flow instruction that began at the given
// address.
virtual void ProcessControlFlowInstructionEnd(uint32_t cf_index) {}
// Handles translation for control flow exec instructions prior to their
// contained ALU/fetch instructions.
virtual void ProcessExecInstructionBegin(const ParsedExecInstruction& instr) {
@ -166,6 +171,9 @@ class ShaderTranslator {
// Accumulated translation errors.
std::vector<Shader::Error> errors_;
// Current control flow dword index.
uint32_t cf_index_ = 0;
// Microcode disassembly buffer, accumulated throughout the translation.
StringBuffer ucode_disasm_buffer_;
// Current line number in the disasm, which can be used for source annotation.