shader: Fix control flow
This commit is contained in:
		| @@ -134,18 +134,27 @@ void IREmitter::SetOFlag(const U1& value) { | ||||
|     Inst(Opcode::SetOFlag, value); | ||||
| } | ||||
|  | ||||
| U1 IREmitter::Condition(IR::Condition cond) { | ||||
|     if (cond == IR::Condition{true}) { | ||||
|         return Imm1(true); | ||||
|     } else if (cond == IR::Condition{false}) { | ||||
|         return Imm1(false); | ||||
| static U1 GetFlowTest(IREmitter& ir, FlowTest flow_test) { | ||||
|     switch (flow_test) { | ||||
|     case FlowTest::T: | ||||
|         return ir.Imm1(true); | ||||
|     case FlowTest::F: | ||||
|         return ir.Imm1(false); | ||||
|     case FlowTest::EQ: | ||||
|         // TODO: Test this | ||||
|         return ir.GetZFlag(); | ||||
|     case FlowTest::NE: | ||||
|         // TODO: Test this | ||||
|         return ir.LogicalNot(ir.GetZFlag()); | ||||
|     default: | ||||
|         throw NotImplementedException("Flow test {}", flow_test); | ||||
|     } | ||||
| } | ||||
|  | ||||
| U1 IREmitter::Condition(IR::Condition cond) { | ||||
|     const FlowTest flow_test{cond.FlowTest()}; | ||||
|     const auto [pred, is_negated]{cond.Pred()}; | ||||
|     if (flow_test == FlowTest::T) { | ||||
|         return GetPred(pred, is_negated); | ||||
|     } | ||||
|     throw NotImplementedException("Condition {}", cond); | ||||
|     return LogicalAnd(GetPred(pred, is_negated), GetFlowTest(*this, flow_test)); | ||||
| } | ||||
|  | ||||
| F32 IREmitter::GetAttribute(IR::Attribute attribute) { | ||||
|   | ||||
| @@ -4,8 +4,8 @@ | ||||
|  | ||||
| //     opcode name,                                         return type,    arg1 type,      arg2 type,      arg3 type,      arg4 type,      ... | ||||
| OPCODE(Phi,                                                 Opaque,                                                                         ) | ||||
| OPCODE(Void,                                                Void,                                                                           ) | ||||
| OPCODE(Identity,                                            Opaque,         Opaque,                                                         ) | ||||
| OPCODE(Void,                                                Void,                                                                           ) | ||||
|  | ||||
| // Control flow | ||||
| OPCODE(Branch,                                              Void,           Label,                                                          ) | ||||
|   | ||||
| @@ -329,7 +329,6 @@ private: | ||||
|         if (!sibling) { | ||||
|             throw LogicError("Not siblings"); | ||||
|         } | ||||
|  | ||||
|         // goto_stmt and label_stmt are guaranteed to be siblings, eliminate | ||||
|         if (std::next(goto_stmt) == label_stmt) { | ||||
|             // Simply eliminate the goto if the label is next to it | ||||
| @@ -351,9 +350,14 @@ private: | ||||
|         const std::unordered_map labels_map{BuildLabels(blocks)}; | ||||
|         Tree& root{root_stmt.children}; | ||||
|         auto insert_point{root.begin()}; | ||||
|         // Skip all goto variables zero-initialization | ||||
|         std::advance(insert_point, labels_map.size()); | ||||
|  | ||||
|         for (Block* const block : blocks) { | ||||
|             ++insert_point; // Skip label | ||||
|             ++insert_point; // Skip set variable | ||||
|             // Skip label | ||||
|             ++insert_point; | ||||
|             // Skip set variable | ||||
|             ++insert_point; | ||||
|             root.insert(insert_point, *pool.Create(block, &root_stmt)); | ||||
|  | ||||
|             if (block->IsTerminationBlock()) { | ||||
| @@ -391,6 +395,7 @@ private: | ||||
|             labels_map.emplace(block, root.insert(root.end(), *label)); | ||||
|             Statement* const false_stmt{pool.Create(Identity{}, Condition{false})}; | ||||
|             root.push_back(*pool.Create(SetVariable{}, label_id, false_stmt, &root_stmt)); | ||||
|             root.push_front(*pool.Create(SetVariable{}, label_id, false_stmt, &root_stmt)); | ||||
|             ++label_id; | ||||
|         } | ||||
|         return labels_map; | ||||
| @@ -457,10 +462,10 @@ private: | ||||
|         } | ||||
|         body.erase(goto_stmt); | ||||
|  | ||||
|         // Update nested if condition | ||||
|         switch (label_nested_stmt->type) { | ||||
|         case StatementType::If: | ||||
|             label_nested_stmt->cond = pool.Create(Or{}, neg_var, label_nested_stmt->cond); | ||||
|             // Update nested if condition | ||||
|             label_nested_stmt->cond = pool.Create(Or{}, variable, label_nested_stmt->cond); | ||||
|             break; | ||||
|         case StatementType::Loop: | ||||
|             break; | ||||
|   | ||||
| @@ -36,6 +36,10 @@ bool Value::IsIdentity() const noexcept { | ||||
|     return type == Type::Opaque && inst->Opcode() == Opcode::Identity; | ||||
| } | ||||
|  | ||||
| bool Value::IsPhi() const noexcept { | ||||
|     return type == Type::Opaque && inst->Opcode() == Opcode::Phi; | ||||
| } | ||||
|  | ||||
| bool Value::IsEmpty() const noexcept { | ||||
|     return type == Type::Void; | ||||
| } | ||||
| @@ -52,7 +56,7 @@ bool Value::IsLabel() const noexcept { | ||||
| } | ||||
|  | ||||
| IR::Type Value::Type() const noexcept { | ||||
|     if (IsIdentity()) { | ||||
|     if (IsIdentity() || IsPhi()) { | ||||
|         return inst->Arg(0).Type(); | ||||
|     } | ||||
|     if (type == Type::Opaque) { | ||||
|   | ||||
| @@ -33,6 +33,7 @@ public: | ||||
|     explicit Value(f64 value) noexcept; | ||||
|  | ||||
|     [[nodiscard]] bool IsIdentity() const noexcept; | ||||
|     [[nodiscard]] bool IsPhi() const noexcept; | ||||
|     [[nodiscard]] bool IsEmpty() const noexcept; | ||||
|     [[nodiscard]] bool IsImmediate() const noexcept; | ||||
|     [[nodiscard]] bool IsLabel() const noexcept; | ||||
|   | ||||
| @@ -354,7 +354,7 @@ void CFG::AnalyzeCondInst(Block* block, FunctionId function_id, Location pc, | ||||
|     // Impersonate the visited block with a virtual block | ||||
|     *block = std::move(virtual_block); | ||||
|     // Set the end properties of the conditional instruction | ||||
|     conditional_block->end = pc; | ||||
|     conditional_block->end = pc + 1; | ||||
|     conditional_block->end_class = insn_end_class; | ||||
|     // Add a label to the instruction after the conditional instruction | ||||
|     Block* const endif_block{AddLabel(conditional_block, block->stack, pc + 1, function_id)}; | ||||
|   | ||||
| @@ -209,7 +209,7 @@ public: | ||||
|     void P2R_cbuf(u64 insn); | ||||
|     void P2R_imm(u64 insn); | ||||
|     void PBK(); | ||||
|     void PCNT(u64 insn); | ||||
|     void PCNT(); | ||||
|     void PEXIT(u64 insn); | ||||
|     void PIXLD(u64 insn); | ||||
|     void PLONGJMP(u64 insn); | ||||
|   | ||||
| @@ -637,8 +637,8 @@ void TranslatorVisitor::PBK() { | ||||
|     // PBK is a no-op | ||||
| } | ||||
|  | ||||
| void TranslatorVisitor::PCNT(u64) { | ||||
|     ThrowNotImplemented(Opcode::PCNT); | ||||
| void TranslatorVisitor::PCNT() { | ||||
|     // PCNT is a no-op | ||||
| } | ||||
|  | ||||
| void TranslatorVisitor::PEXIT(u64) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user