add new Value variant for string literal. Use arg0 for fmt string

This commit is contained in:
Frodo Baggins 2024-10-05 19:25:04 -07:00
parent 577af02346
commit 6722f2805a
12 changed files with 50 additions and 28 deletions

View File

@ -39,6 +39,8 @@ ArgType Arg(EmitContext& ctx, const IR::Value& arg) {
return arg.ScalarReg(); return arg.ScalarReg();
} else if constexpr (std::is_same_v<ArgType, IR::VectorReg>) { } else if constexpr (std::is_same_v<ArgType, IR::VectorReg>) {
return arg.VectorReg(); return arg.VectorReg();
} else if constexpr (std::is_same_v<ArgType, const char*>) {
return arg.StringLiteral();
} }
} }

View File

@ -50,12 +50,9 @@ void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) {
throw NotImplementedException("Geometry streams"); throw NotImplementedException("Geometry streams");
} }
void EmitDebugPrint(EmitContext& ctx, IR::Inst* inst, Id arg0, Id arg1, Id arg2, Id arg3, Id arg4) { void EmitDebugPrint(EmitContext& ctx, IR::Inst* inst, Id fmt, Id arg0, Id arg1, Id arg2, Id arg3) {
DebugPrintFlags flags = inst->Flags<DebugPrintFlags>(); IR::DebugPrintFlags flags = inst->Flags<IR::DebugPrintFlags>();
const std::string& format_string = ctx.info.string_pool[flags.string_idx]; std::array<Id, IR::DEBUGPRINT_NUM_FORMAT_ARGS> fmt_args = {arg0, arg1, arg2, arg3};
Id fmt = ctx.String(format_string);
std::array<Id, IR::NumArgsOf(IR::Opcode::DebugPrint)> fmt_args = {arg0, arg1, arg2, arg3, arg4};
auto fmt_args_span = std::span<Id>(fmt_args.begin(), fmt_args.begin() + flags.num_args); auto fmt_args_span = std::span<Id>(fmt_args.begin(), fmt_args.begin() + flags.num_args);
ctx.OpDebugPrintf(fmt, fmt_args_span); ctx.OpDebugPrintf(fmt, fmt_args_span);
} }

View File

@ -73,6 +73,8 @@ Id EmitContext::Def(const IR::Value& value) {
return ConstF32(value.F32()); return ConstF32(value.F32());
case IR::Type::F64: case IR::Type::F64:
return Constant(F64[1], value.F64()); return Constant(F64[1], value.F64());
case IR::Type::StringLiteral:
return String(value.StringLiteral());
default: default:
throw NotImplementedException("Immediate type {}", value.Type()); throw NotImplementedException("Immediate type {}", value.Type());
} }

View File

@ -2,12 +2,20 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/bit_field.h" #include "common/bit_field.h"
#include "shader_recompiler/ir/opcodes.h"
#include "src/common/types.h" #include "src/common/types.h"
#pragma once #pragma once
namespace Shader::IR {
constexpr size_t DEBUGPRINT_NUM_FORMAT_ARGS = NumArgsOf(IR::Opcode::DebugPrint) - 1;
union DebugPrintFlags { union DebugPrintFlags {
u32 raw; u32 raw;
BitField<0, 16, u32> string_idx; // For now, only flag is the number of variadic format args actually used
BitField<16, 16, u32> num_args; // So bitfield not really needed
BitField<0, 32, u32> num_args;
}; };
} // namespace Shader::IR

View File

@ -1563,35 +1563,31 @@ void IREmitter::ImageWrite(const Value& handle, const Value& coords, const Value
// Renderdoc accepts format specifiers, e.g. %u, listed here: // Renderdoc accepts format specifiers, e.g. %u, listed here:
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/main/docs/debug_printf.md // https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/main/docs/debug_printf.md
// //
// fmt must be a string literal (pointer is shallow copied into a Value)
// Example usage: // Example usage:
// ir.DebugPrint("invocation xyz: (%u, %u, %u)", // ir.DebugPrint("invocation xyz: (%u, %u, %u)",
// {ir.GetVectorReg(IR::VectorReg::V0), // {ir.GetVectorReg(IR::VectorReg::V0),
// ir.GetVectorReg(IR::VectorReg::V1), // ir.GetVectorReg(IR::VectorReg::V1),
// ir.GetVectorReg(IR::VectorReg::V2)}); // ir.GetVectorReg(IR::VectorReg::V2)});
void IREmitter::DebugPrint(std::string_view format, void IREmitter::DebugPrint(const char* fmt, boost::container::small_vector<Value, 5> format_args) {
boost::container::small_vector<Value, 5> format_args) { std::array<Value, DEBUGPRINT_NUM_FORMAT_ARGS> args;
constexpr size_t PRINT_MAX_ARGS = NumArgsOf(IR::Opcode::DebugPrint);
std::array<Value, PRINT_MAX_ARGS> args;
ASSERT_MSG(format_args.size() < PRINT_MAX_ARGS, "DebugPrint only supports up to {} format args", ASSERT_MSG(format_args.size() < DEBUGPRINT_NUM_FORMAT_ARGS,
PRINT_MAX_ARGS); "DebugPrint only supports up to {} format args", DEBUGPRINT_NUM_FORMAT_ARGS);
for (int i = 0; i < format_args.size(); i++) { for (int i = 0; i < format_args.size(); i++) {
args[i] = format_args[i]; args[i] = format_args[i];
} }
for (int i = format_args.size(); i < PRINT_MAX_ARGS; i++) { for (int i = format_args.size(); i < DEBUGPRINT_NUM_FORMAT_ARGS; i++) {
args[i] = Inst(Opcode::Void); args[i] = Inst(Opcode::Void);
} }
Value val = Inst(Opcode::DebugPrint, args[0], args[1], args[2], args[3], args[4]); IR::Value fmt_val{fmt};
DebugPrintFlags flags; DebugPrintFlags flags;
flags.string_idx.Assign(info.string_pool.size());
info.string_pool.emplace_back(format);
flags.num_args.Assign(format_args.size()); flags.num_args.Assign(format_args.size());
Inst(Opcode::DebugPrint, Flags{flags}, fmt_val, args[0], args[1], args[2], args[3]);
val.Inst()->SetFlags<DebugPrintFlags>(flags);
} }
} // namespace Shader::IR } // namespace Shader::IR

View File

@ -45,7 +45,7 @@ public:
void Epilogue(); void Epilogue();
void Discard(); void Discard();
void Discard(const U1& cond); void Discard(const U1& cond);
void DebugPrint(std::string_view format, boost::container::small_vector<Value, 5> args); void DebugPrint(const char* fmt, boost::container::small_vector<Value, 5> args);
void Barrier(); void Barrier();
void WorkgroupMemoryBarrier(); void WorkgroupMemoryBarrier();

View File

@ -51,6 +51,7 @@ constexpr Type F32x4{Type::F32x4};
constexpr Type F64x2{Type::F64x2}; constexpr Type F64x2{Type::F64x2};
constexpr Type F64x3{Type::F64x3}; constexpr Type F64x3{Type::F64x3};
constexpr Type F64x4{Type::F64x4}; constexpr Type F64x4{Type::F64x4};
constexpr Type StringLiteral{Type::StringLiteral};
constexpr OpcodeMeta META_TABLE[]{ constexpr OpcodeMeta META_TABLE[]{
#define OPCODE(name_token, type_token, ...) \ #define OPCODE(name_token, type_token, ...) \

View File

@ -14,7 +14,7 @@ OPCODE(Prologue, Void,
OPCODE(Epilogue, Void, ) OPCODE(Epilogue, Void, )
OPCODE(Discard, Void, ) OPCODE(Discard, Void, )
OPCODE(DiscardCond, Void, U1, ) OPCODE(DiscardCond, Void, U1, )
OPCODE(DebugPrint, Void, Opaque, Opaque, Opaque, Opaque, Opaque, ) OPCODE(DebugPrint, Void, StringLiteral, Opaque, Opaque, Opaque, Opaque, )
// Constant memory operations // Constant memory operations
OPCODE(ReadConst, U32, U32x2, U32, ) OPCODE(ReadConst, U32, U32x2, U32, )

View File

@ -11,8 +11,7 @@ std::string NameOf(Type type) {
static constexpr std::array names{ static constexpr std::array names{
"Opaque", "Label", "Reg", "Pred", "Attribute", "U1", "U8", "U16", "U32", "Opaque", "Label", "Reg", "Pred", "Attribute", "U1", "U8", "U16", "U32",
"U64", "F16", "F32", "F64", "U32x2", "U32x3", "U32x4", "F16x2", "F16x3", "U64", "F16", "F32", "F64", "U32x2", "U32x3", "U32x4", "F16x2", "F16x3",
"F16x4", "F32x2", "F32x3", "F32x4", "F64x2", "F64x3", "F64x4", "F16x4", "F32x2", "F32x3", "F32x4", "F64x2", "F64x3", "F64x4", "StringLiteral"};
};
const size_t bits{static_cast<size_t>(type)}; const size_t bits{static_cast<size_t>(type)};
if (bits == 0) { if (bits == 0) {
return "Void"; return "Void";

View File

@ -36,6 +36,7 @@ enum class Type {
F64x2 = 1 << 22, F64x2 = 1 << 22,
F64x3 = 1 << 23, F64x3 = 1 << 23,
F64x4 = 1 << 24, F64x4 = 1 << 24,
StringLiteral = 1 << 25,
}; };
DECLARE_ENUM_FLAG_OPERATORS(Type) DECLARE_ENUM_FLAG_OPERATORS(Type)

View File

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <string>
#include "shader_recompiler/ir/value.h" #include "shader_recompiler/ir/value.h"
namespace Shader::IR { namespace Shader::IR {
@ -27,6 +28,8 @@ Value::Value(u64 value) noexcept : type{Type::U64}, imm_u64{value} {}
Value::Value(f64 value) noexcept : type{Type::F64}, imm_f64{value} {} Value::Value(f64 value) noexcept : type{Type::F64}, imm_f64{value} {}
Value::Value(const char* value) noexcept : type{Type::StringLiteral}, string_literal{value} {}
IR::Type Value::Type() const noexcept { IR::Type Value::Type() const noexcept {
if (IsPhi()) { if (IsPhi()) {
// The type of a phi node is stored in its flags // The type of a phi node is stored in its flags
@ -69,6 +72,8 @@ bool Value::operator==(const Value& other) const {
case Type::U64: case Type::U64:
case Type::F64: case Type::F64:
return imm_u64 == other.imm_u64; return imm_u64 == other.imm_u64;
case Type::StringLiteral:
return std::string(string_literal) == other.string_literal;
case Type::U32x2: case Type::U32x2:
case Type::U32x3: case Type::U32x3:
case Type::U32x4: case Type::U32x4:

View File

@ -39,6 +39,7 @@ public:
explicit Value(f32 value) noexcept; explicit Value(f32 value) noexcept;
explicit Value(u64 value) noexcept; explicit Value(u64 value) noexcept;
explicit Value(f64 value) noexcept; explicit Value(f64 value) noexcept;
explicit Value(const char* value) noexcept;
[[nodiscard]] bool IsIdentity() const noexcept; [[nodiscard]] bool IsIdentity() const noexcept;
[[nodiscard]] bool IsPhi() const noexcept; [[nodiscard]] bool IsPhi() const noexcept;
@ -60,6 +61,7 @@ public:
[[nodiscard]] f32 F32() const; [[nodiscard]] f32 F32() const;
[[nodiscard]] u64 U64() const; [[nodiscard]] u64 U64() const;
[[nodiscard]] f64 F64() const; [[nodiscard]] f64 F64() const;
[[nodiscard]] const char* StringLiteral() const;
[[nodiscard]] bool operator==(const Value& other) const; [[nodiscard]] bool operator==(const Value& other) const;
[[nodiscard]] bool operator!=(const Value& other) const; [[nodiscard]] bool operator!=(const Value& other) const;
@ -78,6 +80,7 @@ private:
f32 imm_f32; f32 imm_f32;
u64 imm_u64; u64 imm_u64;
f64 imm_f64; f64 imm_f64;
const char* string_literal;
}; };
}; };
static_assert(static_cast<u32>(IR::Type::Void) == 0, "memset relies on IR::Type being zero"); static_assert(static_cast<u32>(IR::Type::Void) == 0, "memset relies on IR::Type being zero");
@ -348,6 +351,14 @@ inline f64 Value::F64() const {
return imm_f64; return imm_f64;
} }
inline const char* Value::StringLiteral() const {
if (IsIdentity()) {
return inst->Arg(0).StringLiteral();
}
DEBUG_ASSERT(type == Type::StringLiteral);
return string_literal;
}
[[nodiscard]] inline bool IsPhi(const Inst& inst) { [[nodiscard]] inline bool IsPhi(const Inst& inst) {
return inst.GetOpcode() == Opcode::Phi; return inst.GetOpcode() == Opcode::Phi;
} }