Merge pull request #3506 from namkazt/patch-9

shader_decode: Implement partial ATOM/ATOMS instr
This commit is contained in:
Rodrigo Locatti 2020-03-31 00:56:28 -03:00 committed by GitHub
commit c19425ed69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 120 additions and 37 deletions

View File

@ -231,18 +231,6 @@ enum class AtomicOp : u64 {
Or = 6, Or = 6,
Xor = 7, Xor = 7,
Exch = 8, Exch = 8,
};
enum class GlobalAtomicOp : u64 {
Add = 0,
Min = 1,
Max = 2,
Inc = 3,
Dec = 4,
And = 5,
Or = 6,
Xor = 7,
Exch = 8,
SafeAdd = 10, SafeAdd = 10,
}; };
@ -1001,7 +989,7 @@ union Instruction {
} stg; } stg;
union { union {
BitField<52, 4, GlobalAtomicOp> operation; BitField<52, 4, AtomicOp> operation;
BitField<49, 3, GlobalAtomicType> type; BitField<49, 3, GlobalAtomicType> type;
BitField<28, 20, s64> offset; BitField<28, 20, s64> offset;
} atom; } atom;

View File

@ -2114,6 +2114,10 @@ private:
template <const std::string_view& opname, Type type> template <const std::string_view& opname, Type type>
Expression Atomic(Operation operation) { Expression Atomic(Operation operation) {
if ((opname == Func::Min || opname == Func::Max) && type == Type::Int) {
UNIMPLEMENTED_MSG("Unimplemented Min & Max for atomic operations");
return {};
}
return {fmt::format("atomic{}({}, {})", opname, Visit(operation[0]).GetCode(), return {fmt::format("atomic{}({}, {})", opname, Visit(operation[0]).GetCode(),
Visit(operation[1]).As(type)), Visit(operation[1]).As(type)),
type}; type};
@ -2307,6 +2311,8 @@ private:
~Func() = delete; ~Func() = delete;
static constexpr std::string_view Add = "Add"; static constexpr std::string_view Add = "Add";
static constexpr std::string_view Min = "Min";
static constexpr std::string_view Max = "Max";
static constexpr std::string_view And = "And"; static constexpr std::string_view And = "And";
static constexpr std::string_view Or = "Or"; static constexpr std::string_view Or = "Or";
static constexpr std::string_view Xor = "Xor"; static constexpr std::string_view Xor = "Xor";
@ -2457,7 +2463,21 @@ private:
&GLSLDecompiler::AtomicImage<Func::Xor>, &GLSLDecompiler::AtomicImage<Func::Xor>,
&GLSLDecompiler::AtomicImage<Func::Exchange>, &GLSLDecompiler::AtomicImage<Func::Exchange>,
&GLSLDecompiler::Atomic<Func::Exchange, Type::Uint>,
&GLSLDecompiler::Atomic<Func::Add, Type::Uint>, &GLSLDecompiler::Atomic<Func::Add, Type::Uint>,
&GLSLDecompiler::Atomic<Func::Min, Type::Uint>,
&GLSLDecompiler::Atomic<Func::Max, Type::Uint>,
&GLSLDecompiler::Atomic<Func::And, Type::Uint>,
&GLSLDecompiler::Atomic<Func::Or, Type::Uint>,
&GLSLDecompiler::Atomic<Func::Xor, Type::Uint>,
&GLSLDecompiler::Atomic<Func::Exchange, Type::Int>,
&GLSLDecompiler::Atomic<Func::Add, Type::Int>,
&GLSLDecompiler::Atomic<Func::Min, Type::Int>,
&GLSLDecompiler::Atomic<Func::Max, Type::Int>,
&GLSLDecompiler::Atomic<Func::And, Type::Int>,
&GLSLDecompiler::Atomic<Func::Or, Type::Int>,
&GLSLDecompiler::Atomic<Func::Xor, Type::Int>,
&GLSLDecompiler::Branch, &GLSLDecompiler::Branch,
&GLSLDecompiler::BranchIndirect, &GLSLDecompiler::BranchIndirect,

View File

@ -1941,7 +1941,11 @@ private:
return {}; return {};
} }
Expression AtomicAdd(Operation operation) { template <Id (Module::*func)(Id, Id, Id, Id, Id), Type result_type,
Type value_type = result_type>
Expression Atomic(Operation operation) {
const Id type_def = GetTypeDefinition(result_type);
Id pointer; Id pointer;
if (const auto smem = std::get_if<SmemNode>(&*operation[0])) { if (const auto smem = std::get_if<SmemNode>(&*operation[0])) {
pointer = GetSharedMemoryPointer(*smem); pointer = GetSharedMemoryPointer(*smem);
@ -1949,14 +1953,15 @@ private:
pointer = GetGlobalMemoryPointer(*gmem); pointer = GetGlobalMemoryPointer(*gmem);
} else { } else {
UNREACHABLE(); UNREACHABLE();
return {Constant(t_uint, 0), Type::Uint}; return {Constant(type_def, 0), result_type};
} }
const Id scope = Constant(t_uint, static_cast<u32>(spv::Scope::Device)); const Id value = As(Visit(operation[1]), value_type);
const Id semantics = Constant(t_uint, 0U);
const Id value = AsUint(Visit(operation[1])); const Id scope = Constant(t_uint, static_cast<u32>(spv::Scope::Device));
return {OpAtomicIAdd(t_uint, pointer, scope, semantics, value), Type::Uint}; const Id semantics = Constant(type_def, 0);
return {(this->*func)(type_def, pointer, scope, semantics, value), result_type};
} }
Expression Branch(Operation operation) { Expression Branch(Operation operation) {
@ -2545,7 +2550,21 @@ private:
&SPIRVDecompiler::AtomicImageXor, &SPIRVDecompiler::AtomicImageXor,
&SPIRVDecompiler::AtomicImageExchange, &SPIRVDecompiler::AtomicImageExchange,
&SPIRVDecompiler::AtomicAdd, &SPIRVDecompiler::Atomic<&Module::OpAtomicExchange, Type::Uint>,
&SPIRVDecompiler::Atomic<&Module::OpAtomicIAdd, Type::Uint>,
&SPIRVDecompiler::Atomic<&Module::OpAtomicUMin, Type::Uint>,
&SPIRVDecompiler::Atomic<&Module::OpAtomicUMax, Type::Uint>,
&SPIRVDecompiler::Atomic<&Module::OpAtomicAnd, Type::Uint>,
&SPIRVDecompiler::Atomic<&Module::OpAtomicOr, Type::Uint>,
&SPIRVDecompiler::Atomic<&Module::OpAtomicXor, Type::Uint>,
&SPIRVDecompiler::Atomic<&Module::OpAtomicExchange, Type::Int>,
&SPIRVDecompiler::Atomic<&Module::OpAtomicIAdd, Type::Int>,
&SPIRVDecompiler::Atomic<&Module::OpAtomicSMin, Type::Int>,
&SPIRVDecompiler::Atomic<&Module::OpAtomicSMax, Type::Int>,
&SPIRVDecompiler::Atomic<&Module::OpAtomicAnd, Type::Int>,
&SPIRVDecompiler::Atomic<&Module::OpAtomicOr, Type::Int>,
&SPIRVDecompiler::Atomic<&Module::OpAtomicXor, Type::Int>,
&SPIRVDecompiler::Branch, &SPIRVDecompiler::Branch,
&SPIRVDecompiler::BranchIndirect, &SPIRVDecompiler::BranchIndirect,

View File

@ -19,7 +19,6 @@ namespace VideoCommon::Shader {
using Tegra::Shader::AtomicOp; using Tegra::Shader::AtomicOp;
using Tegra::Shader::AtomicType; using Tegra::Shader::AtomicType;
using Tegra::Shader::Attribute; using Tegra::Shader::Attribute;
using Tegra::Shader::GlobalAtomicOp;
using Tegra::Shader::GlobalAtomicType; using Tegra::Shader::GlobalAtomicType;
using Tegra::Shader::Instruction; using Tegra::Shader::Instruction;
using Tegra::Shader::OpCode; using Tegra::Shader::OpCode;
@ -28,6 +27,28 @@ using Tegra::Shader::StoreType;
namespace { namespace {
Node GetAtomOperation(AtomicOp op, bool is_signed, Node memory, Node data) {
const OperationCode operation_code = [op] {
switch (op) {
case AtomicOp::Add:
return OperationCode::AtomicIAdd;
case AtomicOp::Min:
return OperationCode::AtomicIMin;
case AtomicOp::Max:
return OperationCode::AtomicIMax;
case AtomicOp::And:
return OperationCode::AtomicIAnd;
case AtomicOp::Or:
return OperationCode::AtomicIOr;
case AtomicOp::Xor:
return OperationCode::AtomicIXor;
case AtomicOp::Exch:
return OperationCode::AtomicIExchange;
}
}();
return SignedOperation(operation_code, is_signed, std::move(memory), std::move(data));
}
bool IsUnaligned(Tegra::Shader::UniformType uniform_type) { bool IsUnaligned(Tegra::Shader::UniformType uniform_type) {
return uniform_type == Tegra::Shader::UniformType::UnsignedByte || return uniform_type == Tegra::Shader::UniformType::UnsignedByte ||
uniform_type == Tegra::Shader::UniformType::UnsignedShort; uniform_type == Tegra::Shader::UniformType::UnsignedShort;
@ -363,10 +384,13 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
break; break;
} }
case OpCode::Id::ATOM: { case OpCode::Id::ATOM: {
UNIMPLEMENTED_IF_MSG(instr.atom.operation != GlobalAtomicOp::Add, "operation={}", UNIMPLEMENTED_IF_MSG(instr.atom.operation == AtomicOp::Inc ||
static_cast<int>(instr.atom.operation.Value())); instr.atom.operation == AtomicOp::Dec ||
UNIMPLEMENTED_IF_MSG(instr.atom.type != GlobalAtomicType::S32, "type={}", instr.atom.operation == AtomicOp::SafeAdd,
static_cast<int>(instr.atom.type.Value())); "operation={}", static_cast<int>(instr.atom.operation.Value()));
UNIMPLEMENTED_IF_MSG(instr.atom.type == GlobalAtomicType::S64 ||
instr.atom.type == GlobalAtomicType::U64,
"type={}", static_cast<int>(instr.atom.type.Value()));
const auto [real_address, base_address, descriptor] = const auto [real_address, base_address, descriptor] =
TrackGlobalMemory(bb, instr, true, true); TrackGlobalMemory(bb, instr, true, true);
@ -375,25 +399,29 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
break; break;
} }
const bool is_signed =
instr.atoms.type == AtomicType::S32 || instr.atoms.type == AtomicType::S64;
Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor); Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor);
Node value = Operation(OperationCode::AtomicAdd, std::move(gmem), GetRegister(instr.gpr20)); Node value = GetAtomOperation(static_cast<AtomicOp>(instr.atom.operation), is_signed, gmem,
GetRegister(instr.gpr20));
SetRegister(bb, instr.gpr0, std::move(value)); SetRegister(bb, instr.gpr0, std::move(value));
break; break;
} }
case OpCode::Id::ATOMS: { case OpCode::Id::ATOMS: {
UNIMPLEMENTED_IF_MSG(instr.atoms.operation != AtomicOp::Add, "operation={}", UNIMPLEMENTED_IF_MSG(instr.atoms.operation == AtomicOp::Inc ||
static_cast<int>(instr.atoms.operation.Value())); instr.atoms.operation == AtomicOp::Dec,
UNIMPLEMENTED_IF_MSG(instr.atoms.type != AtomicType::U32, "type={}", "operation={}", static_cast<int>(instr.atoms.operation.Value()));
static_cast<int>(instr.atoms.type.Value())); UNIMPLEMENTED_IF_MSG(instr.atoms.type == AtomicType::S64 ||
instr.atoms.type == AtomicType::U64,
"type={}", static_cast<int>(instr.atoms.type.Value()));
const bool is_signed =
instr.atoms.type == AtomicType::S32 || instr.atoms.type == AtomicType::S64;
const s32 offset = instr.atoms.GetImmediateOffset(); const s32 offset = instr.atoms.GetImmediateOffset();
Node address = GetRegister(instr.gpr8); Node address = GetRegister(instr.gpr8);
address = Operation(OperationCode::IAdd, std::move(address), Immediate(offset)); address = Operation(OperationCode::IAdd, std::move(address), Immediate(offset));
Node value =
Node memory = GetSharedMemory(std::move(address)); GetAtomOperation(static_cast<AtomicOp>(instr.atoms.operation), is_signed,
Node data = GetRegister(instr.gpr20); GetSharedMemory(std::move(address)), GetRegister(instr.gpr20));
Node value = Operation(OperationCode::AtomicAdd, std::move(memory), std::move(data));
SetRegister(bb, instr.gpr0, std::move(value)); SetRegister(bb, instr.gpr0, std::move(value));
break; break;
} }

View File

@ -162,7 +162,21 @@ enum class OperationCode {
AtomicImageXor, /// (MetaImage, int[N] coords) -> void AtomicImageXor, /// (MetaImage, int[N] coords) -> void
AtomicImageExchange, /// (MetaImage, int[N] coords) -> void AtomicImageExchange, /// (MetaImage, int[N] coords) -> void
AtomicAdd, /// (memory, {u}int) -> {u}int AtomicUExchange, /// (memory, uint) -> uint
AtomicUAdd, /// (memory, uint) -> uint
AtomicUMin, /// (memory, uint) -> uint
AtomicUMax, /// (memory, uint) -> uint
AtomicUAnd, /// (memory, uint) -> uint
AtomicUOr, /// (memory, uint) -> uint
AtomicUXor, /// (memory, uint) -> uint
AtomicIExchange, /// (memory, int) -> int
AtomicIAdd, /// (memory, int) -> int
AtomicIMin, /// (memory, int) -> int
AtomicIMax, /// (memory, int) -> int
AtomicIAnd, /// (memory, int) -> int
AtomicIOr, /// (memory, int) -> int
AtomicIXor, /// (memory, int) -> int
Branch, /// (uint branch_target) -> void Branch, /// (uint branch_target) -> void
BranchIndirect, /// (uint branch_target) -> void BranchIndirect, /// (uint branch_target) -> void

View File

@ -86,6 +86,20 @@ OperationCode SignedToUnsignedCode(OperationCode operation_code, bool is_signed)
return OperationCode::LogicalUNotEqual; return OperationCode::LogicalUNotEqual;
case OperationCode::LogicalIGreaterEqual: case OperationCode::LogicalIGreaterEqual:
return OperationCode::LogicalUGreaterEqual; return OperationCode::LogicalUGreaterEqual;
case OperationCode::AtomicIExchange:
return OperationCode::AtomicUExchange;
case OperationCode::AtomicIAdd:
return OperationCode::AtomicUAdd;
case OperationCode::AtomicIMin:
return OperationCode::AtomicUMin;
case OperationCode::AtomicIMax:
return OperationCode::AtomicUMax;
case OperationCode::AtomicIAnd:
return OperationCode::AtomicUAnd;
case OperationCode::AtomicIOr:
return OperationCode::AtomicUOr;
case OperationCode::AtomicIXor:
return OperationCode::AtomicUXor;
case OperationCode::INegate: case OperationCode::INegate:
UNREACHABLE_MSG("Can't negate an unsigned integer"); UNREACHABLE_MSG("Can't negate an unsigned integer");
return {}; return {};