summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/frontend')
-rw-r--r--src/shader_recompiler/frontend/ir/attribute.cpp2
-rw-r--r--src/shader_recompiler/frontend/ir/attribute.h2
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.cpp14
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.h4
-rw-r--r--src/shader_recompiler/frontend/ir/microinstruction.cpp3
-rw-r--r--src/shader_recompiler/frontend/ir/opcodes.inc11
-rw-r--r--src/shader_recompiler/frontend/ir/program.h2
-rw-r--r--src/shader_recompiler/frontend/ir/reg.h4
-rw-r--r--src/shader_recompiler/frontend/maxwell/control_flow.cpp31
-rw-r--r--src/shader_recompiler/frontend/maxwell/control_flow.h3
-rw-r--r--src/shader_recompiler/frontend/maxwell/program.cpp1
-rw-r--r--src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp18
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/exit.cpp15
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/exit_program.cpp43
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/impl.h4
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp86
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp16
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp2
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp2
19 files changed, 212 insertions, 51 deletions
diff --git a/src/shader_recompiler/frontend/ir/attribute.cpp b/src/shader_recompiler/frontend/ir/attribute.cpp
index 2fb7d576f..4811242ea 100644
--- a/src/shader_recompiler/frontend/ir/attribute.cpp
+++ b/src/shader_recompiler/frontend/ir/attribute.cpp
@@ -13,7 +13,7 @@ bool IsGeneric(Attribute attribute) noexcept {
13 return attribute >= Attribute::Generic0X && attribute <= Attribute::Generic31X; 13 return attribute >= Attribute::Generic0X && attribute <= Attribute::Generic31X;
14} 14}
15 15
16int GenericAttributeIndex(Attribute attribute) { 16u32 GenericAttributeIndex(Attribute attribute) {
17 if (!IsGeneric(attribute)) { 17 if (!IsGeneric(attribute)) {
18 throw InvalidArgument("Attribute is not generic {}", attribute); 18 throw InvalidArgument("Attribute is not generic {}", attribute);
19 } 19 }
diff --git a/src/shader_recompiler/frontend/ir/attribute.h b/src/shader_recompiler/frontend/ir/attribute.h
index bb2cad6af..34ec7e0cd 100644
--- a/src/shader_recompiler/frontend/ir/attribute.h
+++ b/src/shader_recompiler/frontend/ir/attribute.h
@@ -224,7 +224,7 @@ enum class Attribute : u64 {
224 224
225[[nodiscard]] bool IsGeneric(Attribute attribute) noexcept; 225[[nodiscard]] bool IsGeneric(Attribute attribute) noexcept;
226 226
227[[nodiscard]] int GenericAttributeIndex(Attribute attribute); 227[[nodiscard]] u32 GenericAttributeIndex(Attribute attribute);
228 228
229[[nodiscard]] std::string NameOf(Attribute attribute); 229[[nodiscard]] std::string NameOf(Attribute attribute);
230 230
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
index 958282160..672836c0b 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
@@ -82,6 +82,12 @@ void IREmitter::Return() {
82 Inst(Opcode::Return); 82 Inst(Opcode::Return);
83} 83}
84 84
85void IREmitter::DemoteToHelperInvocation(Block* continue_label) {
86 block->SetBranch(continue_label);
87 continue_label->AddImmediatePredecessor(block);
88 Inst(Opcode::DemoteToHelperInvocation, continue_label);
89}
90
85U32 IREmitter::GetReg(IR::Reg reg) { 91U32 IREmitter::GetReg(IR::Reg reg) {
86 return Inst<U32>(Opcode::GetRegister, reg); 92 return Inst<U32>(Opcode::GetRegister, reg);
87} 93}
@@ -248,6 +254,14 @@ void IREmitter::SetAttribute(IR::Attribute attribute, const F32& value) {
248 Inst(Opcode::SetAttribute, attribute, value); 254 Inst(Opcode::SetAttribute, attribute, value);
249} 255}
250 256
257void IREmitter::SetFragColor(u32 index, u32 component, const F32& value) {
258 Inst(Opcode::SetFragColor, Imm32(index), Imm32(component), value);
259}
260
261void IREmitter::SetFragDepth(const F32& value) {
262 Inst(Opcode::SetFragDepth, value);
263}
264
251U32 IREmitter::WorkgroupIdX() { 265U32 IREmitter::WorkgroupIdX() {
252 return U32{CompositeExtract(Inst(Opcode::WorkgroupId), 0)}; 266 return U32{CompositeExtract(Inst(Opcode::WorkgroupId), 0)};
253} 267}
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h
index 05263fe8b..72af5db37 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.h
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.h
@@ -36,6 +36,7 @@ public:
36 void LoopMerge(Block* merge_block, Block* continue_target); 36 void LoopMerge(Block* merge_block, Block* continue_target);
37 void SelectionMerge(Block* merge_block); 37 void SelectionMerge(Block* merge_block);
38 void Return(); 38 void Return();
39 void DemoteToHelperInvocation(Block* continue_label);
39 40
40 [[nodiscard]] U32 GetReg(IR::Reg reg); 41 [[nodiscard]] U32 GetReg(IR::Reg reg);
41 void SetReg(IR::Reg reg, const U32& value); 42 void SetReg(IR::Reg reg, const U32& value);
@@ -67,6 +68,9 @@ public:
67 [[nodiscard]] F32 GetAttribute(IR::Attribute attribute); 68 [[nodiscard]] F32 GetAttribute(IR::Attribute attribute);
68 void SetAttribute(IR::Attribute attribute, const F32& value); 69 void SetAttribute(IR::Attribute attribute, const F32& value);
69 70
71 void SetFragColor(u32 index, u32 component, const F32& value);
72 void SetFragDepth(const F32& value);
73
70 [[nodiscard]] U32 WorkgroupIdX(); 74 [[nodiscard]] U32 WorkgroupIdX();
71 [[nodiscard]] U32 WorkgroupIdY(); 75 [[nodiscard]] U32 WorkgroupIdY();
72 [[nodiscard]] U32 WorkgroupIdZ(); 76 [[nodiscard]] U32 WorkgroupIdZ();
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp
index 5946105d2..21b7d8a9f 100644
--- a/src/shader_recompiler/frontend/ir/microinstruction.cpp
+++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp
@@ -55,8 +55,11 @@ bool Inst::MayHaveSideEffects() const noexcept {
55 case Opcode::LoopMerge: 55 case Opcode::LoopMerge:
56 case Opcode::SelectionMerge: 56 case Opcode::SelectionMerge:
57 case Opcode::Return: 57 case Opcode::Return:
58 case Opcode::DemoteToHelperInvocation:
58 case Opcode::SetAttribute: 59 case Opcode::SetAttribute:
59 case Opcode::SetAttributeIndexed: 60 case Opcode::SetAttributeIndexed:
61 case Opcode::SetFragColor:
62 case Opcode::SetFragDepth:
60 case Opcode::WriteGlobalU8: 63 case Opcode::WriteGlobalU8:
61 case Opcode::WriteGlobalS8: 64 case Opcode::WriteGlobalS8:
62 case Opcode::WriteGlobalU16: 65 case Opcode::WriteGlobalU16:
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc
index 9052a4903..593faca52 100644
--- a/src/shader_recompiler/frontend/ir/opcodes.inc
+++ b/src/shader_recompiler/frontend/ir/opcodes.inc
@@ -13,6 +13,7 @@ OPCODE(BranchConditional, Void, U1,
13OPCODE(LoopMerge, Void, Label, Label, ) 13OPCODE(LoopMerge, Void, Label, Label, )
14OPCODE(SelectionMerge, Void, Label, ) 14OPCODE(SelectionMerge, Void, Label, )
15OPCODE(Return, Void, ) 15OPCODE(Return, Void, )
16OPCODE(DemoteToHelperInvocation, Void, Label, )
16 17
17// Context getters/setters 18// Context getters/setters
18OPCODE(GetRegister, U32, Reg, ) 19OPCODE(GetRegister, U32, Reg, )
@@ -28,10 +29,12 @@ OPCODE(GetCbufS16, U32, U32,
28OPCODE(GetCbufU32, U32, U32, U32, ) 29OPCODE(GetCbufU32, U32, U32, U32, )
29OPCODE(GetCbufF32, F32, U32, U32, ) 30OPCODE(GetCbufF32, F32, U32, U32, )
30OPCODE(GetCbufU64, U64, U32, U32, ) 31OPCODE(GetCbufU64, U64, U32, U32, )
31OPCODE(GetAttribute, U32, Attribute, ) 32OPCODE(GetAttribute, F32, Attribute, )
32OPCODE(SetAttribute, Void, Attribute, U32, ) 33OPCODE(SetAttribute, Void, Attribute, F32, )
33OPCODE(GetAttributeIndexed, U32, U32, ) 34OPCODE(GetAttributeIndexed, F32, U32, )
34OPCODE(SetAttributeIndexed, Void, U32, U32, ) 35OPCODE(SetAttributeIndexed, Void, U32, F32, )
36OPCODE(SetFragColor, Void, U32, U32, F32, )
37OPCODE(SetFragDepth, Void, F32, )
35OPCODE(GetZFlag, U1, Void, ) 38OPCODE(GetZFlag, U1, Void, )
36OPCODE(GetSFlag, U1, Void, ) 39OPCODE(GetSFlag, U1, Void, )
37OPCODE(GetCFlag, U1, Void, ) 40OPCODE(GetCFlag, U1, Void, )
diff --git a/src/shader_recompiler/frontend/ir/program.h b/src/shader_recompiler/frontend/ir/program.h
index bce8b19b3..733513c8b 100644
--- a/src/shader_recompiler/frontend/ir/program.h
+++ b/src/shader_recompiler/frontend/ir/program.h
@@ -10,6 +10,7 @@
10 10
11#include "shader_recompiler/frontend/ir/basic_block.h" 11#include "shader_recompiler/frontend/ir/basic_block.h"
12#include "shader_recompiler/shader_info.h" 12#include "shader_recompiler/shader_info.h"
13#include "shader_recompiler/stage.h"
13 14
14namespace Shader::IR { 15namespace Shader::IR {
15 16
@@ -17,6 +18,7 @@ struct Program {
17 BlockList blocks; 18 BlockList blocks;
18 BlockList post_order_blocks; 19 BlockList post_order_blocks;
19 Info info; 20 Info info;
21 Stage stage{};
20}; 22};
21 23
22[[nodiscard]] std::string DumpProgram(const Program& program); 24[[nodiscard]] std::string DumpProgram(const Program& program);
diff --git a/src/shader_recompiler/frontend/ir/reg.h b/src/shader_recompiler/frontend/ir/reg.h
index 8fea05f7b..3845ec5fb 100644
--- a/src/shader_recompiler/frontend/ir/reg.h
+++ b/src/shader_recompiler/frontend/ir/reg.h
@@ -293,12 +293,12 @@ constexpr size_t NUM_REGS = 256;
293 return reg + (-num); 293 return reg + (-num);
294} 294}
295 295
296[[nodiscard]] constexpr Reg operator++(Reg& reg) { 296constexpr Reg operator++(Reg& reg) {
297 reg = reg + 1; 297 reg = reg + 1;
298 return reg; 298 return reg;
299} 299}
300 300
301[[nodiscard]] constexpr Reg operator++(Reg& reg, int) { 301constexpr Reg operator++(Reg& reg, int) {
302 const Reg copy{reg}; 302 const Reg copy{reg};
303 reg = reg + 1; 303 reg = reg + 1;
304 return copy; 304 return copy;
diff --git a/src/shader_recompiler/frontend/maxwell/control_flow.cpp b/src/shader_recompiler/frontend/maxwell/control_flow.cpp
index 715c0e92d..4f6707fae 100644
--- a/src/shader_recompiler/frontend/maxwell/control_flow.cpp
+++ b/src/shader_recompiler/frontend/maxwell/control_flow.cpp
@@ -104,6 +104,7 @@ bool HasFlowTest(Opcode opcode) {
104 case Opcode::EXIT: 104 case Opcode::EXIT:
105 case Opcode::JMP: 105 case Opcode::JMP:
106 case Opcode::JMX: 106 case Opcode::JMX:
107 case Opcode::KIL:
107 case Opcode::BRK: 108 case Opcode::BRK:
108 case Opcode::CONT: 109 case Opcode::CONT:
109 case Opcode::LONGJMP: 110 case Opcode::LONGJMP:
@@ -287,6 +288,13 @@ CFG::AnalysisState CFG::AnalyzeInst(Block* block, FunctionId function_id, Locati
287 block->end = pc; 288 block->end = pc;
288 return AnalysisState::Branch; 289 return AnalysisState::Branch;
289 } 290 }
291 case Opcode::KIL: {
292 const Predicate pred{inst.Pred()};
293 const auto ir_pred{static_cast<IR::Pred>(pred.index)};
294 const IR::Condition cond{inst.branch.flow_test, ir_pred, pred.negated};
295 AnalyzeCondInst(block, function_id, pc, EndClass::Kill, cond);
296 return AnalysisState::Branch;
297 }
290 case Opcode::PBK: 298 case Opcode::PBK:
291 case Opcode::PCNT: 299 case Opcode::PCNT:
292 case Opcode::PEXIT: 300 case Opcode::PEXIT:
@@ -324,13 +332,12 @@ CFG::AnalysisState CFG::AnalyzeInst(Block* block, FunctionId function_id, Locati
324 return AnalysisState::Continue; 332 return AnalysisState::Continue;
325 } 333 }
326 const IR::Condition cond{static_cast<IR::Pred>(pred.index), pred.negated}; 334 const IR::Condition cond{static_cast<IR::Pred>(pred.index), pred.negated};
327 AnalyzeCondInst(block, function_id, pc, EndClass::Branch, cond, true); 335 AnalyzeCondInst(block, function_id, pc, EndClass::Branch, cond);
328 return AnalysisState::Branch; 336 return AnalysisState::Branch;
329} 337}
330 338
331void CFG::AnalyzeCondInst(Block* block, FunctionId function_id, Location pc, 339void CFG::AnalyzeCondInst(Block* block, FunctionId function_id, Location pc,
332 EndClass insn_end_class, IR::Condition cond, 340 EndClass insn_end_class, IR::Condition cond) {
333 bool visit_conditional_inst) {
334 if (block->begin != pc) { 341 if (block->begin != pc) {
335 // If the block doesn't start in the conditional instruction 342 // If the block doesn't start in the conditional instruction
336 // mark it as a label to visit it later 343 // mark it as a label to visit it later
@@ -356,14 +363,16 @@ void CFG::AnalyzeCondInst(Block* block, FunctionId function_id, Location pc,
356 // Impersonate the visited block with a virtual block 363 // Impersonate the visited block with a virtual block
357 *block = std::move(virtual_block); 364 *block = std::move(virtual_block);
358 // Set the end properties of the conditional instruction 365 // Set the end properties of the conditional instruction
359 conditional_block->end = visit_conditional_inst ? (pc + 1) : pc; 366 conditional_block->end = pc + 1;
360 conditional_block->end_class = insn_end_class; 367 conditional_block->end_class = insn_end_class;
361 // Add a label to the instruction after the conditional instruction 368 // Add a label to the instruction after the conditional instruction
362 Block* const endif_block{AddLabel(conditional_block, block->stack, pc + 1, function_id)}; 369 Block* const endif_block{AddLabel(conditional_block, block->stack, pc + 1, function_id)};
363 // Branch to the next instruction from the virtual block 370 // Branch to the next instruction from the virtual block
364 block->branch_false = endif_block; 371 block->branch_false = endif_block;
365 // And branch to it from the conditional instruction if it is a branch 372 // And branch to it from the conditional instruction if it is a branch or a kill instruction
366 if (insn_end_class == EndClass::Branch) { 373 // Kill instructions are considered a branch because they demote to a helper invocation and
374 // execution may continue.
375 if (insn_end_class == EndClass::Branch || insn_end_class == EndClass::Kill) {
367 conditional_block->cond = IR::Condition{true}; 376 conditional_block->cond = IR::Condition{true};
368 conditional_block->branch_true = endif_block; 377 conditional_block->branch_true = endif_block;
369 conditional_block->branch_false = nullptr; 378 conditional_block->branch_false = nullptr;
@@ -415,7 +424,7 @@ CFG::AnalysisState CFG::AnalyzeEXIT(Block* block, FunctionId function_id, Locati
415 throw NotImplementedException("Conditional EXIT with PEXIT token"); 424 throw NotImplementedException("Conditional EXIT with PEXIT token");
416 } 425 }
417 const IR::Condition cond{flow_test, static_cast<IR::Pred>(pred.index), pred.negated}; 426 const IR::Condition cond{flow_test, static_cast<IR::Pred>(pred.index), pred.negated};
418 AnalyzeCondInst(block, function_id, pc, EndClass::Exit, cond, false); 427 AnalyzeCondInst(block, function_id, pc, EndClass::Exit, cond);
419 return AnalysisState::Branch; 428 return AnalysisState::Branch;
420 } 429 }
421 if (const std::optional<Location> exit_pc{block->stack.Peek(Token::PEXIT)}) { 430 if (const std::optional<Location> exit_pc{block->stack.Peek(Token::PEXIT)}) {
@@ -425,7 +434,7 @@ CFG::AnalysisState CFG::AnalyzeEXIT(Block* block, FunctionId function_id, Locati
425 block->branch_false = nullptr; 434 block->branch_false = nullptr;
426 return AnalysisState::Branch; 435 return AnalysisState::Branch;
427 } 436 }
428 block->end = pc; 437 block->end = pc + 1;
429 block->end_class = EndClass::Exit; 438 block->end_class = EndClass::Exit;
430 return AnalysisState::Branch; 439 return AnalysisState::Branch;
431} 440}
@@ -505,6 +514,12 @@ std::string CFG::Dot() const {
505 node_uid); 514 node_uid);
506 ++node_uid; 515 ++node_uid;
507 break; 516 break;
517 case EndClass::Kill:
518 dot += fmt::format("\t\t{}->N{};\n", name, node_uid);
519 dot += fmt::format("\t\tN{} [label=\"Kill\"][shape=square][style=stripped];\n",
520 node_uid);
521 ++node_uid;
522 break;
508 } 523 }
509 } 524 }
510 if (function.entrypoint == 8) { 525 if (function.entrypoint == 8) {
diff --git a/src/shader_recompiler/frontend/maxwell/control_flow.h b/src/shader_recompiler/frontend/maxwell/control_flow.h
index fe74f210f..22f134194 100644
--- a/src/shader_recompiler/frontend/maxwell/control_flow.h
+++ b/src/shader_recompiler/frontend/maxwell/control_flow.h
@@ -29,6 +29,7 @@ enum class EndClass {
29 Call, 29 Call,
30 Exit, 30 Exit,
31 Return, 31 Return,
32 Kill,
32}; 33};
33 34
34enum class Token { 35enum class Token {
@@ -130,7 +131,7 @@ private:
130 AnalysisState AnalyzeInst(Block* block, FunctionId function_id, Location pc); 131 AnalysisState AnalyzeInst(Block* block, FunctionId function_id, Location pc);
131 132
132 void AnalyzeCondInst(Block* block, FunctionId function_id, Location pc, EndClass insn_end_class, 133 void AnalyzeCondInst(Block* block, FunctionId function_id, Location pc, EndClass insn_end_class,
133 IR::Condition cond, bool visit_conditional_inst); 134 IR::Condition cond);
134 135
135 /// Return true when the branch instruction is confirmed to be a branch 136 /// Return true when the branch instruction is confirmed to be a branch
136 bool AnalyzeBranch(Block* block, FunctionId function_id, Location pc, Instruction inst, 137 bool AnalyzeBranch(Block* block, FunctionId function_id, Location pc, Instruction inst,
diff --git a/src/shader_recompiler/frontend/maxwell/program.cpp b/src/shader_recompiler/frontend/maxwell/program.cpp
index 8bfa64326..0074eb89b 100644
--- a/src/shader_recompiler/frontend/maxwell/program.cpp
+++ b/src/shader_recompiler/frontend/maxwell/program.cpp
@@ -32,6 +32,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
32 IR::Program program; 32 IR::Program program;
33 program.blocks = VisitAST(inst_pool, block_pool, env, cfg); 33 program.blocks = VisitAST(inst_pool, block_pool, env, cfg);
34 program.post_order_blocks = PostOrder(program.blocks); 34 program.post_order_blocks = PostOrder(program.blocks);
35 program.stage = env.ShaderStage();
35 RemoveUnreachableBlocks(program); 36 RemoveUnreachableBlocks(program);
36 37
37 // Replace instructions before the SSA rewrite 38 // Replace instructions before the SSA rewrite
diff --git a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
index 5f5d9cf17..cec03e73e 100644
--- a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
+++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
@@ -45,6 +45,7 @@ enum class StatementType {
45 Loop, 45 Loop,
46 Break, 46 Break,
47 Return, 47 Return,
48 Kill,
48 Function, 49 Function,
49 Identity, 50 Identity,
50 Not, 51 Not,
@@ -70,6 +71,7 @@ struct If {};
70struct Loop {}; 71struct Loop {};
71struct Break {}; 72struct Break {};
72struct Return {}; 73struct Return {};
74struct Kill {};
73struct FunctionTag {}; 75struct FunctionTag {};
74struct Identity {}; 76struct Identity {};
75struct Not {}; 77struct Not {};
@@ -93,6 +95,7 @@ struct Statement : ListBaseHook {
93 Statement(Break, Statement* cond_, Statement* up_) 95 Statement(Break, Statement* cond_, Statement* up_)
94 : cond{cond_}, up{up_}, type{StatementType::Break} {} 96 : cond{cond_}, up{up_}, type{StatementType::Break} {}
95 Statement(Return) : type{StatementType::Return} {} 97 Statement(Return) : type{StatementType::Return} {}
98 Statement(Kill) : type{StatementType::Kill} {}
96 Statement(FunctionTag) : children{}, type{StatementType::Function} {} 99 Statement(FunctionTag) : children{}, type{StatementType::Function} {}
97 Statement(Identity, IR::Condition cond_) : guest_cond{cond_}, type{StatementType::Identity} {} 100 Statement(Identity, IR::Condition cond_) : guest_cond{cond_}, type{StatementType::Identity} {}
98 Statement(Not, Statement* op_) : op{op_}, type{StatementType::Not} {} 101 Statement(Not, Statement* op_) : op{op_}, type{StatementType::Not} {}
@@ -174,6 +177,9 @@ std::string DumpTree(const Tree& tree, u32 indentation = 0) {
174 case StatementType::Return: 177 case StatementType::Return:
175 ret += fmt::format("{} return;\n", indent); 178 ret += fmt::format("{} return;\n", indent);
176 break; 179 break;
180 case StatementType::Kill:
181 ret += fmt::format("{} kill;\n", indent);
182 break;
177 case StatementType::SetVariable: 183 case StatementType::SetVariable:
178 ret += fmt::format("{} goto_L{} = {};\n", indent, stmt->id, DumpExpr(stmt->op)); 184 ret += fmt::format("{} goto_L{} = {};\n", indent, stmt->id, DumpExpr(stmt->op));
179 break; 185 break;
@@ -424,6 +430,9 @@ private:
424 gotos.push_back(root.insert(ip, *goto_stmt)); 430 gotos.push_back(root.insert(ip, *goto_stmt));
425 break; 431 break;
426 } 432 }
433 case Flow::EndClass::Kill:
434 root.insert(ip, *pool.Create(Kill{}));
435 break;
427 } 436 }
428 } 437 }
429 } 438 }
@@ -729,6 +738,15 @@ private:
729 current_block = nullptr; 738 current_block = nullptr;
730 break; 739 break;
731 } 740 }
741 case StatementType::Kill: {
742 if (!current_block) {
743 current_block = block_pool.Create(inst_pool);
744 block_list.push_back(current_block);
745 }
746 IR::IREmitter{*current_block}.DemoteToHelperInvocation(continue_block);
747 current_block = nullptr;
748 break;
749 }
732 default: 750 default:
733 throw NotImplementedException("Statement type {}", stmt.type); 751 throw NotImplementedException("Statement type {}", stmt.type);
734 } 752 }
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/exit.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/exit.cpp
deleted file mode 100644
index e98bbd0d1..000000000
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/exit.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/common_types.h"
6#include "shader_recompiler/exception.h"
7#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
8
9namespace Shader::Maxwell {
10
11void TranslatorVisitor::EXIT(u64) {
12 ir.Exit();
13}
14
15} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/exit_program.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/exit_program.cpp
new file mode 100644
index 000000000..ea9b33da9
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/exit_program.cpp
@@ -0,0 +1,43 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/common_types.h"
6#include "shader_recompiler/exception.h"
7#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
8
9namespace Shader::Maxwell {
10namespace {
11void ExitFragment(TranslatorVisitor& v) {
12 const ProgramHeader sph{v.env.SPH()};
13 IR::Reg src_reg{IR::Reg::R0};
14 for (u32 render_target = 0; render_target < 8; ++render_target) {
15 const std::array<bool, 4> mask{sph.ps.EnabledOutputComponents(render_target)};
16 for (u32 component = 0; component < 4; ++component) {
17 if (!mask[component]) {
18 continue;
19 }
20 v.ir.SetFragColor(render_target, component, v.F(src_reg));
21 ++src_reg;
22 }
23 }
24 if (sph.ps.omap.sample_mask != 0) {
25 throw NotImplementedException("Sample mask");
26 }
27 if (sph.ps.omap.depth != 0) {
28 throw NotImplementedException("Fragment depth");
29 }
30}
31} // Anonymous namespace
32
33void TranslatorVisitor::EXIT() {
34 switch (env.ShaderStage()) {
35 case Stage::Fragment:
36 ExitFragment(*this);
37 break;
38 default:
39 break;
40 }
41}
42
43} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
index e3e298c3b..ed81d9c36 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
@@ -108,7 +108,7 @@ public:
108 void DSETP_reg(u64 insn); 108 void DSETP_reg(u64 insn);
109 void DSETP_cbuf(u64 insn); 109 void DSETP_cbuf(u64 insn);
110 void DSETP_imm(u64 insn); 110 void DSETP_imm(u64 insn);
111 void EXIT(u64 insn); 111 void EXIT();
112 void F2F_reg(u64 insn); 112 void F2F_reg(u64 insn);
113 void F2F_cbuf(u64 insn); 113 void F2F_cbuf(u64 insn);
114 void F2F_imm(u64 insn); 114 void F2F_imm(u64 insn);
@@ -220,7 +220,7 @@ public:
220 void JCAL(u64 insn); 220 void JCAL(u64 insn);
221 void JMP(u64 insn); 221 void JMP(u64 insn);
222 void JMX(u64 insn); 222 void JMX(u64 insn);
223 void KIL(u64 insn); 223 void KIL();
224 void LD(u64 insn); 224 void LD(u64 insn);
225 void LDC(u64 insn); 225 void LDC(u64 insn);
226 void LDG(u64 insn); 226 void LDG(u64 insn);
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp
index ad97786d4..2922145ee 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp
@@ -11,6 +11,13 @@
11 11
12namespace Shader::Maxwell { 12namespace Shader::Maxwell {
13namespace { 13namespace {
14enum class Size : u64 {
15 B32,
16 B64,
17 B96,
18 B128,
19};
20
14enum class InterpolationMode : u64 { 21enum class InterpolationMode : u64 {
15 Pass, 22 Pass,
16 Multiply, 23 Multiply,
@@ -23,8 +30,85 @@ enum class SampleMode : u64 {
23 Centroid, 30 Centroid,
24 Offset, 31 Offset,
25}; 32};
33
34int NumElements(Size size) {
35 switch (size) {
36 case Size::B32:
37 return 1;
38 case Size::B64:
39 return 2;
40 case Size::B96:
41 return 3;
42 case Size::B128:
43 return 4;
44 }
45 throw InvalidArgument("Invalid size {}", size);
46}
26} // Anonymous namespace 47} // Anonymous namespace
27 48
49void TranslatorVisitor::ALD(u64 insn) {
50 union {
51 u64 raw;
52 BitField<0, 8, IR::Reg> dest_reg;
53 BitField<8, 8, IR::Reg> index_reg;
54 BitField<20, 10, u64> absolute_offset;
55 BitField<20, 11, s64> relative_offset;
56 BitField<39, 8, IR::Reg> stream_reg;
57 BitField<32, 1, u64> o;
58 BitField<31, 1, u64> patch;
59 BitField<47, 2, Size> size;
60 } const ald{insn};
61
62 if (ald.o != 0) {
63 throw NotImplementedException("O");
64 }
65 if (ald.patch != 0) {
66 throw NotImplementedException("P");
67 }
68 if (ald.index_reg != IR::Reg::RZ) {
69 throw NotImplementedException("Indexed");
70 }
71 const u64 offset{ald.absolute_offset.Value()};
72 if (offset % 4 != 0) {
73 throw NotImplementedException("Unaligned absolute offset {}", offset);
74 }
75 const int num_elements{NumElements(ald.size)};
76 for (int element = 0; element < num_elements; ++element) {
77 F(ald.dest_reg + element, ir.GetAttribute(IR::Attribute{offset / 4 + element}));
78 }
79}
80
81void TranslatorVisitor::AST(u64 insn) {
82 union {
83 u64 raw;
84 BitField<0, 8, IR::Reg> src_reg;
85 BitField<8, 8, IR::Reg> index_reg;
86 BitField<20, 10, u64> absolute_offset;
87 BitField<20, 11, s64> relative_offset;
88 BitField<31, 1, u64> patch;
89 BitField<39, 8, IR::Reg> stream_reg;
90 BitField<47, 2, Size> size;
91 } const ast{insn};
92
93 if (ast.patch != 0) {
94 throw NotImplementedException("P");
95 }
96 if (ast.stream_reg != IR::Reg::RZ) {
97 throw NotImplementedException("Stream store");
98 }
99 if (ast.index_reg != IR::Reg::RZ) {
100 throw NotImplementedException("Indexed store");
101 }
102 const u64 offset{ast.absolute_offset.Value()};
103 if (offset % 4 != 0) {
104 throw NotImplementedException("Unaligned absolute offset {}", offset);
105 }
106 const int num_elements{NumElements(ast.size)};
107 for (int element = 0; element < num_elements; ++element) {
108 ir.SetAttribute(IR::Attribute{offset / 4 + element}, F(ast.src_reg + element));
109 }
110}
111
28void TranslatorVisitor::IPA(u64 insn) { 112void TranslatorVisitor::IPA(u64 insn) {
29 // IPA is the instruction used to read varyings from a fragment shader. 113 // IPA is the instruction used to read varyings from a fragment shader.
30 // gl_FragCoord is mapped to the gl_Position attribute. 114 // gl_FragCoord is mapped to the gl_Position attribute.
@@ -51,7 +135,7 @@ void TranslatorVisitor::IPA(u64 insn) {
51 // } 135 // }
52 const bool is_indexed{ipa.idx != 0 && ipa.index_reg != IR::Reg::RZ}; 136 const bool is_indexed{ipa.idx != 0 && ipa.index_reg != IR::Reg::RZ};
53 if (is_indexed) { 137 if (is_indexed) {
54 throw NotImplementedException("IPA.IDX"); 138 throw NotImplementedException("IDX");
55 } 139 }
56 140
57 const IR::Attribute attribute{ipa.attribute}; 141 const IR::Attribute attribute{ipa.attribute};
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp
index 9675cef54..59252bcc5 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp
@@ -17,14 +17,6 @@ void TranslatorVisitor::AL2P(u64) {
17 ThrowNotImplemented(Opcode::AL2P); 17 ThrowNotImplemented(Opcode::AL2P);
18} 18}
19 19
20void TranslatorVisitor::ALD(u64) {
21 ThrowNotImplemented(Opcode::ALD);
22}
23
24void TranslatorVisitor::AST(u64) {
25 ThrowNotImplemented(Opcode::AST);
26}
27
28void TranslatorVisitor::ATOM_cas(u64) { 20void TranslatorVisitor::ATOM_cas(u64) {
29 ThrowNotImplemented(Opcode::ATOM_cas); 21 ThrowNotImplemented(Opcode::ATOM_cas);
30} 22}
@@ -153,10 +145,6 @@ void TranslatorVisitor::DSETP_imm(u64) {
153 ThrowNotImplemented(Opcode::DSETP_imm); 145 ThrowNotImplemented(Opcode::DSETP_imm);
154} 146}
155 147
156void TranslatorVisitor::EXIT(u64) {
157 throw LogicError("Visting EXIT instruction");
158}
159
160void TranslatorVisitor::F2F_reg(u64) { 148void TranslatorVisitor::F2F_reg(u64) {
161 ThrowNotImplemented(Opcode::F2F_reg); 149 ThrowNotImplemented(Opcode::F2F_reg);
162} 150}
@@ -345,8 +333,8 @@ void TranslatorVisitor::JMX(u64) {
345 ThrowNotImplemented(Opcode::JMX); 333 ThrowNotImplemented(Opcode::JMX);
346} 334}
347 335
348void TranslatorVisitor::KIL(u64) { 336void TranslatorVisitor::KIL() {
349 ThrowNotImplemented(Opcode::KIL); 337 // KIL is a no-op
350} 338}
351 339
352void TranslatorVisitor::LD(u64) { 340void TranslatorVisitor::LD(u64) {
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp
index 98d9f4c64..0fbb87ec4 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp
@@ -215,7 +215,7 @@ void TranslatorVisitor::TEX(u64 insn) {
215 BitField<36, 13, u64> cbuf_offset; 215 BitField<36, 13, u64> cbuf_offset;
216 } const tex{insn}; 216 } const tex{insn};
217 217
218 Impl(*this, insn, tex.aoffi != 0, tex.blod, tex.lc != 0, static_cast<u32>(tex.cbuf_offset)); 218 Impl(*this, insn, tex.aoffi != 0, tex.blod, tex.lc != 0, static_cast<u32>(tex.cbuf_offset * 4));
219} 219}
220 220
221void TranslatorVisitor::TEX_b(u64 insn) { 221void TranslatorVisitor::TEX_b(u64 insn) {
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp
index ac1615b00..54f0df754 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp
@@ -70,7 +70,7 @@ IR::F32 ReadArray(TranslatorVisitor& v, const IR::U32& value) {
70 70
71IR::Value Sample(TranslatorVisitor& v, u64 insn) { 71IR::Value Sample(TranslatorVisitor& v, u64 insn) {
72 const Encoding texs{insn}; 72 const Encoding texs{insn};
73 const IR::U32 handle{v.ir.Imm32(static_cast<u32>(texs.cbuf_offset))}; 73 const IR::U32 handle{v.ir.Imm32(static_cast<u32>(texs.cbuf_offset * 4))};
74 const IR::F32 zero{v.ir.Imm32(0.0f)}; 74 const IR::F32 zero{v.ir.Imm32(0.0f)};
75 const IR::Reg reg_a{texs.src_reg_a}; 75 const IR::Reg reg_a{texs.src_reg_a};
76 const IR::Reg reg_b{texs.src_reg_b}; 76 const IR::Reg reg_b{texs.src_reg_b};