diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index ad18caedd..a2ec00bdc 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h @@ -49,9 +49,7 @@ void EmitPrologue(EmitContext& ctx); void EmitEpilogue(EmitContext& ctx); void EmitDiscard(EmitContext& ctx); void EmitDiscardCond(EmitContext& ctx, Id condition); -void EmitVaArg(EmitContext& ctx, IR::Inst* inst, Id arg, Id next); -Id EmitStringLiteral(EmitContext& ctx, IR::Inst* inst); -void EmitDebugPrint(EmitContext& ctx, IR::Inst* inst, Id fmt); +void EmitDebugPrint(EmitContext& ctx, IR::Inst* inst, Id arg0, Id arg1, Id arg2, Id arg3, Id arg4); void EmitBarrier(EmitContext& ctx); void EmitWorkgroupMemoryBarrier(EmitContext& ctx); void EmitDeviceMemoryBarrier(EmitContext& ctx); diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp index ce3f303d9..1cc7ad08d 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp @@ -55,45 +55,15 @@ void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) { throw NotImplementedException("Geometry streams"); } -static bool isEmptyInst(IR::Value val) { - if (auto* inst = val.TryInstRecursive()) { - return inst->GetOpcode() == IR::Opcode::Void; - } - return false; -} +void EmitDebugPrint(EmitContext& ctx, IR::Inst* inst, Id arg0, Id arg1, Id arg2, Id arg3, Id arg4) { + DebugPrintFlags flags = inst->Flags(); + const std::string& format_string = ctx.info.string_pool[flags.string_idx]; + Id fmt = ctx.String(format_string); -void EmitVaArg(EmitContext& ctx, IR::Inst* inst, Id arg, Id next) { - IR::Value next_val = inst->Arg(1); - u32 va_arglist_idx; - if (isEmptyInst(next_val)) { - va_arglist_idx = ctx.va_arg_lists.size(); - ctx.va_arg_lists.emplace_back(); - } else { - va_arglist_idx = next_val.Inst()->Flags().va_arg_idx; - } - - ctx.va_arg_lists[va_arglist_idx].push_back(arg); - auto va_info = inst->Flags(); - va_info.va_arg_idx.Assign(va_arglist_idx); - inst->SetFlags(va_info); -} - -Id EmitStringLiteral(EmitContext& ctx, IR::Inst* inst) { - // ctx. - return ctx.String(inst->StringLiteral()); -} - -void EmitDebugPrint(EmitContext& ctx, IR::Inst* inst, Id fmt) { - IR::Value arglist = inst->Arg(1); - boost::container::small_vector fmt_arg_operands; - if (!isEmptyInst(arglist)) { - u32 va_arglist_idx = arglist.Inst()->Flags().va_arg_idx; - const auto& va_arglist = ctx.va_arg_lists[va_arglist_idx]; - // reverse the order - std::copy(va_arglist.rbegin(), va_arglist.rend(), std::back_inserter(fmt_arg_operands)); - } - - ctx.OpDebugPrintf(fmt, fmt_arg_operands); + std::array fmt_args = {arg0, arg1, arg2, arg3, arg4}; + const std::span fmt_args_span = + std::span(fmt_args.begin(), fmt_args.begin() + flags.num_args); + ctx.OpDebugPrintf(fmt, fmt_args_span); } } // namespace Shader::Backend::SPIRV diff --git a/src/shader_recompiler/frontend/structured_control_flow.cpp b/src/shader_recompiler/frontend/structured_control_flow.cpp index bf5ba6bce..b696106d9 100644 --- a/src/shader_recompiler/frontend/structured_control_flow.cpp +++ b/src/shader_recompiler/frontend/structured_control_flow.cpp @@ -644,7 +644,7 @@ private: } case StatementType::SetVariable: { ensure_block(); - IR::IREmitter ir{*current_block}; + IR::IREmitter ir{*current_block, info}; ir.SetGotoVariable(stmt.id, VisitExpr(ir, *stmt.op)); break; } @@ -653,7 +653,7 @@ private: IR::Block* const merge_block{MergeBlock(parent, stmt)}; // Implement if header block - IR::IREmitter ir{*current_block}; + IR::IREmitter ir{*current_block, info}; const IR::U1 cond{ir.ConditionRef(VisitExpr(ir, *stmt.cond))}; const size_t if_node_index{syntax_list.size()}; @@ -703,7 +703,7 @@ private: Visit(stmt, merge_block, continue_block); // The continue block is located at the end of the loop - IR::IREmitter ir{*continue_block}; + IR::IREmitter ir{*continue_block, info}; const IR::U1 cond{ir.ConditionRef(VisitExpr(ir, *stmt.cond))}; IR::Block* const body_block{syntax_list.at(body_block_index).data.block}; @@ -739,7 +739,7 @@ private: ensure_block(); IR::Block* const skip_block{MergeBlock(parent, stmt)}; - IR::IREmitter ir{*current_block}; + IR::IREmitter ir{*current_block, info}; const IR::U1 cond{ir.ConditionRef(VisitExpr(ir, *stmt.cond))}; current_block->AddBranch(break_block); current_block->AddBranch(skip_block); @@ -759,7 +759,7 @@ private: case StatementType::Return: { ensure_block(); IR::Block* return_block{block_pool.Create(inst_pool)}; - IR::IREmitter{*return_block}.Epilogue(); + IR::IREmitter{*return_block, info}.Epilogue(); current_block->AddBranch(return_block); auto& merge{syntax_list.emplace_back()}; @@ -773,7 +773,7 @@ private: case StatementType::Kill: { ensure_block(); IR::Block* demote_block{MergeBlock(parent, stmt)}; - IR::IREmitter{*current_block}.Discard(); + IR::IREmitter{*current_block, info}.Discard(); current_block->AddBranch(demote_block); current_block = demote_block; diff --git a/src/shader_recompiler/frontend/translate/translate.cpp b/src/shader_recompiler/frontend/translate/translate.cpp index cfef5858a..bf5397427 100644 --- a/src/shader_recompiler/frontend/translate/translate.cpp +++ b/src/shader_recompiler/frontend/translate/translate.cpp @@ -19,7 +19,8 @@ namespace Shader::Gcn { Translator::Translator(IR::Block* block_, Info& info_, const RuntimeInfo& runtime_info_, const Profile& profile_) - : ir{*block_, block_->begin()}, info{info_}, runtime_info{runtime_info_}, profile{profile_} {} + : ir{*block_, block_->begin(), info_}, info{info_}, runtime_info{runtime_info_}, + profile{profile_} {} void Translator::EmitPrologue() { ir.Prologue(); diff --git a/src/shader_recompiler/info.h b/src/shader_recompiler/info.h index 739214ec9..c6c3f442d 100644 --- a/src/shader_recompiler/info.h +++ b/src/shader_recompiler/info.h @@ -179,6 +179,9 @@ struct Info { std::span user_data; Stage stage; + using StringPool = boost::container::small_vector; + StringPool string_pool; + u64 pgm_hash{}; VAddr pgm_base; bool has_storage_images{}; diff --git a/src/shader_recompiler/ir/debug_print.h b/src/shader_recompiler/ir/debug_print.h index 5e1bf43b3..82b0e036d 100644 --- a/src/shader_recompiler/ir/debug_print.h +++ b/src/shader_recompiler/ir/debug_print.h @@ -1,10 +1,10 @@ #include "common/bit_field.h" -#include "src/common/enum.h" +#include "src/common/types.h" #pragma once -union VariadicArgInfo { +union DebugPrintFlags { u32 raw; - - BitField<0, 12, u32> va_arg_idx; + BitField<0, 16, u32> string_idx; + BitField<16, 16, u32> num_args; }; \ No newline at end of file diff --git a/src/shader_recompiler/ir/ir_emitter.cpp b/src/shader_recompiler/ir/ir_emitter.cpp index 3d6772bea..45f1608d8 100644 --- a/src/shader_recompiler/ir/ir_emitter.cpp +++ b/src/shader_recompiler/ir/ir_emitter.cpp @@ -1,15 +1,13 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include -#include #include #include -#include "common/assert.h" #include "shader_recompiler/exception.h" #include "shader_recompiler/ir/debug_print.h" #include "shader_recompiler/ir/ir_emitter.h" -#include "shader_recompiler/ir/opcodes.h" #include "shader_recompiler/ir/value.h" namespace Shader::IR { @@ -1558,72 +1556,27 @@ void IREmitter::ImageWrite(const Value& handle, const Value& coords, const Value Inst(Opcode::ImageWrite, Flags{info}, handle, coords, color); } -Value IREmitter::VaArg(Value arg, Value next) { - return Inst(Opcode::VaArg, arg, next); -} - -Value IREmitter::StringLiteral(std::string_view s) { - Value val = Inst(Opcode::StringLiteral); - val.Inst()->SetStringLiteral(s); - return val; -} - -void IREmitter::DebugPrint(std::string_view format, boost::container::small_vector args, +void IREmitter::DebugPrint(std::string_view format, + boost::container::small_vector format_args, bool infer_specifiers) { - auto infer_specifier = [&](IR::Value arg) -> const char* { - switch (arg.Type()) { - case Shader::IR::Type::U1: - case Shader::IR::Type::U8: - case Shader::IR::Type::U16: - case Shader::IR::Type::U32: - return "%u"; - case Shader::IR::Type::U64: - return "%lu"; - case Shader::IR::Type::F16: - case Shader::IR::Type::F32: - case Shader::IR::Type::F64: - return "%lf"; - case Shader::IR::Type::U32x2: - return "%v2u"; - case Shader::IR::Type::U32x3: - return "%v3u"; - case Shader::IR::Type::U32x4: - return "%v4u"; - case Shader::IR::Type::F16x2: - case Shader::IR::Type::F32x2: - case Shader::IR::Type::F64x2: - return "%v2f"; - case Shader::IR::Type::F16x3: - case Shader::IR::Type::F32x3: - case Shader::IR::Type::F64x3: - return "%v3f"; - case Shader::IR::Type::F16x4: - case Shader::IR::Type::F32x4: - case Shader::IR::Type::F64x4: - return "%v4f"; - case Shader::IR::Type::Void: - case Shader::IR::Type::Opaque: - case Shader::IR::Type::ScalarReg: - case Shader::IR::Type::VectorReg: - case Shader::IR::Type::Attribute: - case Shader::IR::Type::SystemValue: - UNREACHABLE(); - } - }; + std::array args; - if (infer_specifiers) { - UNREACHABLE(); - // need to fmt the format string with dynamic sized array of format spec strings - // could use param pack for this function, but less flexible + for (int i = 0; i < format_args.size(); i++) { + args[i] = format_args[i]; } - Value arg_list = Inst(Opcode::Void); - for (Value arg : args) { - arg_list = VaArg(arg, arg_list); + for (int i = format_args.size(); i < 4; i++) { + args[i] = Inst(Opcode::Void); } - Value string_val = StringLiteral(format); - Inst(Opcode::DebugPrint, string_val, arg_list); + Value val = Inst(Opcode::DebugPrint, args[0], args[1], args[2], args[3], args[4]); + DebugPrintFlags flags; + + flags.string_idx.Assign(info.string_pool.size()); + info.string_pool.emplace_back(format); + flags.num_args.Assign(format_args.size()); + + val.Inst()->SetFlags(flags); } } // namespace Shader::IR diff --git a/src/shader_recompiler/ir/ir_emitter.h b/src/shader_recompiler/ir/ir_emitter.h index eb0df2d3f..5364c13ec 100644 --- a/src/shader_recompiler/ir/ir_emitter.h +++ b/src/shader_recompiler/ir/ir_emitter.h @@ -8,6 +8,7 @@ #include #include +#include "shader_recompiler/info.h" #include "shader_recompiler/ir/attribute.h" #include "shader_recompiler/ir/basic_block.h" #include "shader_recompiler/ir/condition.h" @@ -17,9 +18,10 @@ namespace Shader::IR { class IREmitter { public: - explicit IREmitter(Block& block_) : block{&block_}, insertion_point{block->end()} {} - explicit IREmitter(Block& block_, Block::iterator insertion_point_) - : block{&block_}, insertion_point{insertion_point_} {} + explicit IREmitter(Block& block_, Shader::Info& info_) + : block{&block_}, insertion_point{block->end()}, info(info_) {} + explicit IREmitter(Block& block_, Block::iterator insertion_point_, Shader::Info& info_) + : block{&block_}, insertion_point{insertion_point_}, info(info_) {} Block* block; @@ -45,11 +47,7 @@ public: void Epilogue(); void Discard(); void Discard(const U1& cond); - - Value VaArg(Value arg, Value next); - Value StringLiteral(std::string_view s); - - void DebugPrint(std::string_view format, boost::container::small_vector args, + void DebugPrint(std::string_view format, boost::container::small_vector args, bool infer_specifiers = false); void Barrier(); @@ -320,6 +318,7 @@ public: private: IR::Block::iterator insertion_point; + Shader::Info& info; template T Inst(Opcode op, Args... args) { diff --git a/src/shader_recompiler/ir/microinstruction.cpp b/src/shader_recompiler/ir/microinstruction.cpp index 8098389e4..3b114bf3d 100644 --- a/src/shader_recompiler/ir/microinstruction.cpp +++ b/src/shader_recompiler/ir/microinstruction.cpp @@ -14,8 +14,6 @@ namespace Shader::IR { Inst::Inst(IR::Opcode op_, u32 flags_) noexcept : op{op_}, flags{flags_} { if (op == Opcode::Phi) { std::construct_at(&phi_args); - } else if (op == Opcode::StringLiteral) { - std::construct_at(&string_literal); } else { std::construct_at(&args); } @@ -24,8 +22,6 @@ Inst::Inst(IR::Opcode op_, u32 flags_) noexcept : op{op_}, flags{flags_} { Inst::Inst(const Inst& base) : op{base.op}, flags{base.flags} { if (base.op == Opcode::Phi) { throw NotImplementedException("Copying phi node"); - } else if (base.op == Opcode::StringLiteral) { - std::construct_at(&string_literal, base.string_literal); } else { std::construct_at(&args); const size_t num_args{base.NumArgs()}; @@ -38,8 +34,6 @@ Inst::Inst(const Inst& base) : op{base.op}, flags{base.flags} { Inst::~Inst() { if (op == Opcode::Phi) { std::destroy_at(&phi_args); - } else if (op == Opcode::StringLiteral) { - std::destroy_at(&string_literal); } else { std::destroy_at(&args); } @@ -107,9 +101,6 @@ bool Inst::AreAllArgsImmediates() const { if (op == Opcode::Phi) { UNREACHABLE_MSG("Testing for all arguments are immediates on phi instruction"); } - if (op == Opcode::StringLiteral) { - UNREACHABLE_MSG("Testing for all arguments are immediates on StringLiteral instruction"); - } return std::all_of(args.begin(), args.begin() + NumArgs(), [](const IR::Value& value) { return value.IsImmediate(); }); } @@ -131,8 +122,6 @@ void Inst::SetArg(size_t index, Value value) { } if (op == Opcode::Phi) { phi_args[index].second = value; - } else if (op == Opcode::StringLiteral) { - UNREACHABLE_MSG("SetArg on StringLiteral instruction"); } else { args[index] = value; } @@ -169,8 +158,6 @@ void Inst::ClearArgs() { } } phi_args.clear(); - } else if (op == Opcode::StringLiteral) { - string_literal.clear(); } else { for (auto& value : args) { if (!value.IsImmediate()) { @@ -196,9 +183,6 @@ void Inst::ReplaceOpcode(IR::Opcode opcode) { if (opcode == IR::Opcode::Phi) { UNREACHABLE_MSG("Cannot transition into Phi"); } - if (op == IR::Opcode::StringLiteral || opcode == IR::Opcode::StringLiteral) { - UNREACHABLE_MSG("Cannot transition to or from StringLiteral"); - } if (op == Opcode::Phi) { // Transition out of phi arguments into non-phi std::destroy_at(&phi_args); diff --git a/src/shader_recompiler/ir/opcodes.inc b/src/shader_recompiler/ir/opcodes.inc index 1e3be0671..34cf30e72 100644 --- a/src/shader_recompiler/ir/opcodes.inc +++ b/src/shader_recompiler/ir/opcodes.inc @@ -14,9 +14,7 @@ OPCODE(Prologue, Void, OPCODE(Epilogue, Void, ) OPCODE(Discard, Void, ) OPCODE(DiscardCond, Void, U1, ) -OPCODE(DebugPrint, Void, Opaque, Opaque, ) -OPCODE(VaArg, Opaque, Opaque, Opaque ) -OPCODE(StringLiteral, Opaque, ) +OPCODE(DebugPrint, Void, Opaque, Opaque, Opaque, Opaque, Opaque, ) // Constant memory operations OPCODE(ReadConst, U32, U32x2, U32, ) diff --git a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp index db0d75f0c..64b3d2d5c 100644 --- a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp +++ b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp @@ -377,7 +377,7 @@ void PatchBufferInstruction(IR::Block& block, IR::Inst& inst, Info& info, const auto inst_info = inst.Flags(); // Replace handle with binding index in buffer resource list. - IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; + IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst), info}; inst.SetArg(0, ir.Imm32(binding)); ASSERT(!buffer.add_tid_enable); @@ -436,7 +436,7 @@ void PatchTextureBufferInstruction(IR::Block& block, IR::Inst& inst, Info& info, }); // Replace handle with binding index in texture buffer resource list. - IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; + IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst), info}; inst.SetArg(0, ir.Imm32(binding)); ASSERT(!buffer.swizzle_enable && !buffer.add_tid_enable); } @@ -534,7 +534,7 @@ void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descrip image_binding |= (sampler_binding << 16); // Patch image handle - IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; + IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst), info}; inst.SetArg(0, ir.Imm32(image_binding)); // No need to patch coordinates if we are just querying. @@ -667,7 +667,7 @@ void PatchDataRingInstruction(IR::Block& block, IR::Inst& inst, Info& info, }(); // Patch instruction. - IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; + IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst), info}; inst.SetArg(0, ir.Imm32(gds_addr >> 2)); inst.SetArg(1, ir.Imm32(binding)); } diff --git a/src/shader_recompiler/ir/value.h b/src/shader_recompiler/ir/value.h index c5dd5f5b4..db939eaa5 100644 --- a/src/shader_recompiler/ir/value.h +++ b/src/shader_recompiler/ir/value.h @@ -6,11 +6,9 @@ #include #include #include -#include #include #include #include -#include #include #include "common/assert.h" @@ -148,7 +146,6 @@ public: if (op == IR::Opcode::Phi) { return phi_args[index].second; } else { - ASSERT(op != IR::Opcode::StringLiteral); return args[index]; } } @@ -161,16 +158,6 @@ public: /// Add phi operand to a phi instruction. void AddPhiOperand(Block* predecessor, const Value& value); - [[nodiscard]] std::string_view StringLiteral() const { - ASSERT(op == IR::Opcode::StringLiteral); - return string_literal; - } - - void SetStringLiteral(std::string_view s) noexcept { - ASSERT(op == IR::Opcode::StringLiteral); - string_literal = s; - } - void Invalidate(); void ClearArgs(); @@ -220,7 +207,6 @@ private: NonTriviallyDummy dummy{}; boost::container::small_vector, 2> phi_args; std::array args; - boost::container::string string_literal; }; }; static_assert(sizeof(Inst) <= 128, "Inst size unintentionally increased");