Merge pull request #2784 from ReinUsesLisp/smem
shader_ir: Implement shared memory
This commit is contained in:
commit
b31880dc5e
|
@ -325,6 +325,7 @@ public:
|
|||
DeclareRegisters();
|
||||
DeclarePredicates();
|
||||
DeclareLocalMemory();
|
||||
DeclareSharedMemory();
|
||||
DeclareInternalFlags();
|
||||
DeclareInputAttributes();
|
||||
DeclareOutputAttributes();
|
||||
|
@ -499,6 +500,13 @@ private:
|
|||
code.AddNewLine();
|
||||
}
|
||||
|
||||
void DeclareSharedMemory() {
|
||||
if (stage != ProgramType::Compute) {
|
||||
return;
|
||||
}
|
||||
code.AddLine("shared uint {}[];", GetSharedMemory());
|
||||
}
|
||||
|
||||
void DeclareInternalFlags() {
|
||||
for (u32 flag = 0; flag < static_cast<u32>(InternalFlag::Amount); flag++) {
|
||||
const auto flag_code = static_cast<InternalFlag>(flag);
|
||||
|
@ -881,6 +889,12 @@ private:
|
|||
Type::Uint};
|
||||
}
|
||||
|
||||
if (const auto smem = std::get_if<SmemNode>(&*node)) {
|
||||
return {
|
||||
fmt::format("{}[{} >> 2]", GetSharedMemory(), Visit(smem->GetAddress()).AsUint()),
|
||||
Type::Uint};
|
||||
}
|
||||
|
||||
if (const auto internal_flag = std::get_if<InternalFlagNode>(&*node)) {
|
||||
return {GetInternalFlag(internal_flag->GetFlag()), Type::Bool};
|
||||
}
|
||||
|
@ -1286,6 +1300,11 @@ private:
|
|||
target = {
|
||||
fmt::format("{}[{} >> 2]", GetLocalMemory(), Visit(lmem->GetAddress()).AsUint()),
|
||||
Type::Uint};
|
||||
} else if (const auto smem = std::get_if<SmemNode>(&*dest)) {
|
||||
ASSERT(stage == ProgramType::Compute);
|
||||
target = {
|
||||
fmt::format("{}[{} >> 2]", GetSharedMemory(), Visit(smem->GetAddress()).AsUint()),
|
||||
Type::Uint};
|
||||
} else if (const auto gmem = std::get_if<GmemNode>(&*dest)) {
|
||||
const std::string real = Visit(gmem->GetRealAddress()).AsUint();
|
||||
const std::string base = Visit(gmem->GetBaseAddress()).AsUint();
|
||||
|
@ -2175,6 +2194,10 @@ private:
|
|||
return "lmem_" + suffix;
|
||||
}
|
||||
|
||||
std::string GetSharedMemory() const {
|
||||
return fmt::format("smem_{}", suffix);
|
||||
}
|
||||
|
||||
std::string GetInternalFlag(InternalFlag flag) const {
|
||||
constexpr std::array InternalFlagNames = {"zero_flag", "sign_flag", "carry_flag",
|
||||
"overflow_flag"};
|
||||
|
|
|
@ -35,7 +35,7 @@ u32 GetUniformTypeElementsCount(Tegra::Shader::UniformType uniform_type) {
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
} // Anonymous namespace
|
||||
|
||||
u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
|
||||
const Instruction instr = {program_code[pc]};
|
||||
|
@ -106,16 +106,17 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::LD_L: {
|
||||
LOG_DEBUG(HW_GPU, "LD_L cache management mode: {}",
|
||||
static_cast<u64>(instr.ld_l.unknown.Value()));
|
||||
|
||||
const auto GetLmem = [&](s32 offset) {
|
||||
case OpCode::Id::LD_L:
|
||||
LOG_DEBUG(HW_GPU, "LD_L cache management mode: {}", static_cast<u64>(instr.ld_l.unknown));
|
||||
[[fallthrough]];
|
||||
case OpCode::Id::LD_S: {
|
||||
const auto GetMemory = [&](s32 offset) {
|
||||
ASSERT(offset % 4 == 0);
|
||||
const Node immediate_offset = Immediate(static_cast<s32>(instr.smem_imm) + offset);
|
||||
const Node address = Operation(OperationCode::IAdd, NO_PRECISE, GetRegister(instr.gpr8),
|
||||
immediate_offset);
|
||||
return GetLocalMemory(address);
|
||||
return opcode->get().GetId() == OpCode::Id::LD_S ? GetSharedMemory(address)
|
||||
: GetLocalMemory(address);
|
||||
};
|
||||
|
||||
switch (instr.ldst_sl.type.Value()) {
|
||||
|
@ -135,14 +136,16 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
|
|||
return 0;
|
||||
}
|
||||
}();
|
||||
for (u32 i = 0; i < count; ++i)
|
||||
SetTemporary(bb, i, GetLmem(i * 4));
|
||||
for (u32 i = 0; i < count; ++i)
|
||||
for (u32 i = 0; i < count; ++i) {
|
||||
SetTemporary(bb, i, GetMemory(i * 4));
|
||||
}
|
||||
for (u32 i = 0; i < count; ++i) {
|
||||
SetRegister(bb, instr.gpr0.Value() + i, GetTemporary(i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("LD_L Unhandled type: {}",
|
||||
UNIMPLEMENTED_MSG("{} Unhandled type: {}", opcode->get().GetName(),
|
||||
static_cast<u32>(instr.ldst_sl.type.Value()));
|
||||
}
|
||||
break;
|
||||
|
@ -209,27 +212,34 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
|
|||
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::ST_L: {
|
||||
case OpCode::Id::ST_L:
|
||||
LOG_DEBUG(HW_GPU, "ST_L cache management mode: {}",
|
||||
static_cast<u64>(instr.st_l.cache_management.Value()));
|
||||
|
||||
const auto GetLmemAddr = [&](s32 offset) {
|
||||
[[fallthrough]];
|
||||
case OpCode::Id::ST_S: {
|
||||
const auto GetAddress = [&](s32 offset) {
|
||||
ASSERT(offset % 4 == 0);
|
||||
const Node immediate = Immediate(static_cast<s32>(instr.smem_imm) + offset);
|
||||
return Operation(OperationCode::IAdd, NO_PRECISE, GetRegister(instr.gpr8), immediate);
|
||||
};
|
||||
|
||||
const auto set_memory = opcode->get().GetId() == OpCode::Id::ST_L
|
||||
? &ShaderIR::SetLocalMemory
|
||||
: &ShaderIR::SetSharedMemory;
|
||||
|
||||
switch (instr.ldst_sl.type.Value()) {
|
||||
case Tegra::Shader::StoreType::Bits128:
|
||||
SetLocalMemory(bb, GetLmemAddr(12), GetRegister(instr.gpr0.Value() + 3));
|
||||
SetLocalMemory(bb, GetLmemAddr(8), GetRegister(instr.gpr0.Value() + 2));
|
||||
(this->*set_memory)(bb, GetAddress(12), GetRegister(instr.gpr0.Value() + 3));
|
||||
(this->*set_memory)(bb, GetAddress(8), GetRegister(instr.gpr0.Value() + 2));
|
||||
[[fallthrough]];
|
||||
case Tegra::Shader::StoreType::Bits64:
|
||||
SetLocalMemory(bb, GetLmemAddr(4), GetRegister(instr.gpr0.Value() + 1));
|
||||
(this->*set_memory)(bb, GetAddress(4), GetRegister(instr.gpr0.Value() + 1));
|
||||
[[fallthrough]];
|
||||
case Tegra::Shader::StoreType::Bits32:
|
||||
SetLocalMemory(bb, GetLmemAddr(0), GetRegister(instr.gpr0));
|
||||
(this->*set_memory)(bb, GetAddress(0), GetRegister(instr.gpr0));
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("ST_L Unhandled type: {}",
|
||||
UNIMPLEMENTED_MSG("{} unhandled type: {}", opcode->get().GetName(),
|
||||
static_cast<u32>(instr.ldst_sl.type.Value()));
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -206,12 +206,13 @@ class PredicateNode;
|
|||
class AbufNode;
|
||||
class CbufNode;
|
||||
class LmemNode;
|
||||
class SmemNode;
|
||||
class GmemNode;
|
||||
class CommentNode;
|
||||
|
||||
using NodeData =
|
||||
std::variant<OperationNode, ConditionalNode, GprNode, ImmediateNode, InternalFlagNode,
|
||||
PredicateNode, AbufNode, CbufNode, LmemNode, GmemNode, CommentNode>;
|
||||
PredicateNode, AbufNode, CbufNode, LmemNode, SmemNode, GmemNode, CommentNode>;
|
||||
using Node = std::shared_ptr<NodeData>;
|
||||
using Node4 = std::array<Node, 4>;
|
||||
using NodeBlock = std::vector<Node>;
|
||||
|
@ -583,6 +584,19 @@ private:
|
|||
Node address;
|
||||
};
|
||||
|
||||
/// Shared memory node
|
||||
class SmemNode final {
|
||||
public:
|
||||
explicit SmemNode(Node address) : address{std::move(address)} {}
|
||||
|
||||
const Node& GetAddress() const {
|
||||
return address;
|
||||
}
|
||||
|
||||
private:
|
||||
Node address;
|
||||
};
|
||||
|
||||
/// Global memory node
|
||||
class GmemNode final {
|
||||
public:
|
||||
|
|
|
@ -137,6 +137,10 @@ Node ShaderIR::GetLocalMemory(Node address) {
|
|||
return MakeNode<LmemNode>(std::move(address));
|
||||
}
|
||||
|
||||
Node ShaderIR::GetSharedMemory(Node address) {
|
||||
return MakeNode<SmemNode>(std::move(address));
|
||||
}
|
||||
|
||||
Node ShaderIR::GetTemporary(u32 id) {
|
||||
return GetRegister(Register::ZeroIndex + 1 + id);
|
||||
}
|
||||
|
@ -378,6 +382,11 @@ void ShaderIR::SetLocalMemory(NodeBlock& bb, Node address, Node value) {
|
|||
Operation(OperationCode::Assign, GetLocalMemory(std::move(address)), std::move(value)));
|
||||
}
|
||||
|
||||
void ShaderIR::SetSharedMemory(NodeBlock& bb, Node address, Node value) {
|
||||
bb.push_back(
|
||||
Operation(OperationCode::Assign, GetSharedMemory(std::move(address)), std::move(value)));
|
||||
}
|
||||
|
||||
void ShaderIR::SetTemporary(NodeBlock& bb, u32 id, Node value) {
|
||||
SetRegister(bb, Register::ZeroIndex + 1 + id, std::move(value));
|
||||
}
|
||||
|
|
|
@ -208,6 +208,8 @@ private:
|
|||
Node GetInternalFlag(InternalFlag flag, bool negated = false);
|
||||
/// Generates a node representing a local memory address
|
||||
Node GetLocalMemory(Node address);
|
||||
/// Generates a node representing a shared memory address
|
||||
Node GetSharedMemory(Node address);
|
||||
/// Generates a temporary, internally it uses a post-RZ register
|
||||
Node GetTemporary(u32 id);
|
||||
|
||||
|
@ -217,8 +219,10 @@ private:
|
|||
void SetPredicate(NodeBlock& bb, u64 dest, Node src);
|
||||
/// Sets an internal flag. src value must be a bool-evaluated node
|
||||
void SetInternalFlag(NodeBlock& bb, InternalFlag flag, Node value);
|
||||
/// Sets a local memory address. address and value must be a number-evaluated node
|
||||
/// Sets a local memory address with a value.
|
||||
void SetLocalMemory(NodeBlock& bb, Node address, Node value);
|
||||
/// Sets a shared memory address with a value.
|
||||
void SetSharedMemory(NodeBlock& bb, Node address, Node value);
|
||||
/// Sets a temporary. Internally it uses a post-RZ register
|
||||
void SetTemporary(NodeBlock& bb, u32 id, Node value);
|
||||
|
||||
|
|
Reference in New Issue