Merge pull request #2738 from lioncash/shader-ir
shader-ir: Minor cleanup-related changes
This commit is contained in:
commit
63bda67a34
|
@ -46,12 +46,12 @@ void ShaderIR::Decode() {
|
||||||
coverage_end = shader_info.end;
|
coverage_end = shader_info.end;
|
||||||
if (shader_info.decompilable) {
|
if (shader_info.decompilable) {
|
||||||
disable_flow_stack = true;
|
disable_flow_stack = true;
|
||||||
const auto insert_block = ([this](NodeBlock& nodes, u32 label) {
|
const auto insert_block = [this](NodeBlock& nodes, u32 label) {
|
||||||
if (label == exit_branch) {
|
if (label == exit_branch) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
basic_blocks.insert({label, nodes});
|
basic_blocks.insert({label, nodes});
|
||||||
});
|
};
|
||||||
const auto& blocks = shader_info.blocks;
|
const auto& blocks = shader_info.blocks;
|
||||||
NodeBlock current_block;
|
NodeBlock current_block;
|
||||||
u32 current_label = exit_branch;
|
u32 current_label = exit_branch;
|
||||||
|
@ -103,7 +103,7 @@ void ShaderIR::DecodeRangeInner(NodeBlock& bb, u32 begin, u32 end) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderIR::InsertControlFlow(NodeBlock& bb, const ShaderBlock& block) {
|
void ShaderIR::InsertControlFlow(NodeBlock& bb, const ShaderBlock& block) {
|
||||||
const auto apply_conditions = ([&](const Condition& cond, Node n) -> Node {
|
const auto apply_conditions = [&](const Condition& cond, Node n) -> Node {
|
||||||
Node result = n;
|
Node result = n;
|
||||||
if (cond.cc != ConditionCode::T) {
|
if (cond.cc != ConditionCode::T) {
|
||||||
result = Conditional(GetConditionCode(cond.cc), {result});
|
result = Conditional(GetConditionCode(cond.cc), {result});
|
||||||
|
@ -117,7 +117,7 @@ void ShaderIR::InsertControlFlow(NodeBlock& bb, const ShaderBlock& block) {
|
||||||
result = Conditional(GetPredicate(pred, is_neg), {result});
|
result = Conditional(GetPredicate(pred, is_neg), {result});
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
};
|
||||||
if (block.branch.address < 0) {
|
if (block.branch.address < 0) {
|
||||||
if (block.branch.kills) {
|
if (block.branch.kills) {
|
||||||
Node n = Operation(OperationCode::Discard);
|
Node n = Operation(OperationCode::Discard);
|
||||||
|
|
|
@ -95,10 +95,10 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
|
||||||
const Node op_b =
|
const Node op_b =
|
||||||
GetConstBufferIndirect(instr.cbuf36.index, instr.cbuf36.GetOffset() + 4, index);
|
GetConstBufferIndirect(instr.cbuf36.index, instr.cbuf36.GetOffset() + 4, index);
|
||||||
|
|
||||||
SetTemporal(bb, 0, op_a);
|
SetTemporary(bb, 0, op_a);
|
||||||
SetTemporal(bb, 1, op_b);
|
SetTemporary(bb, 1, op_b);
|
||||||
SetRegister(bb, instr.gpr0, GetTemporal(0));
|
SetRegister(bb, instr.gpr0, GetTemporary(0));
|
||||||
SetRegister(bb, instr.gpr0.Value() + 1, GetTemporal(1));
|
SetRegister(bb, instr.gpr0.Value() + 1, GetTemporary(1));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -136,9 +136,9 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
for (u32 i = 0; i < count; ++i)
|
for (u32 i = 0; i < count; ++i)
|
||||||
SetTemporal(bb, i, GetLmem(i * 4));
|
SetTemporary(bb, i, GetLmem(i * 4));
|
||||||
for (u32 i = 0; i < count; ++i)
|
for (u32 i = 0; i < count; ++i)
|
||||||
SetRegister(bb, instr.gpr0.Value() + i, GetTemporal(i));
|
SetRegister(bb, instr.gpr0.Value() + i, GetTemporary(i));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -172,10 +172,10 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
|
||||||
Operation(OperationCode::UAdd, NO_PRECISE, real_address_base, it_offset);
|
Operation(OperationCode::UAdd, NO_PRECISE, real_address_base, it_offset);
|
||||||
const Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor);
|
const Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor);
|
||||||
|
|
||||||
SetTemporal(bb, i, gmem);
|
SetTemporary(bb, i, gmem);
|
||||||
}
|
}
|
||||||
for (u32 i = 0; i < count; ++i) {
|
for (u32 i = 0; i < count; ++i) {
|
||||||
SetRegister(bb, instr.gpr0.Value() + i, GetTemporal(i));
|
SetRegister(bb, instr.gpr0.Value() + i, GetTemporary(i));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -253,11 +253,11 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
|
||||||
TrackAndGetGlobalMemory(bb, instr, true);
|
TrackAndGetGlobalMemory(bb, instr, true);
|
||||||
|
|
||||||
// Encode in temporary registers like this: real_base_address, {registers_to_be_written...}
|
// Encode in temporary registers like this: real_base_address, {registers_to_be_written...}
|
||||||
SetTemporal(bb, 0, real_address_base);
|
SetTemporary(bb, 0, real_address_base);
|
||||||
|
|
||||||
const u32 count = GetUniformTypeElementsCount(type);
|
const u32 count = GetUniformTypeElementsCount(type);
|
||||||
for (u32 i = 0; i < count; ++i) {
|
for (u32 i = 0; i < count; ++i) {
|
||||||
SetTemporal(bb, i + 1, GetRegister(instr.gpr0.Value() + i));
|
SetTemporary(bb, i + 1, GetRegister(instr.gpr0.Value() + i));
|
||||||
}
|
}
|
||||||
for (u32 i = 0; i < count; ++i) {
|
for (u32 i = 0; i < count; ++i) {
|
||||||
const Node it_offset = Immediate(i * 4);
|
const Node it_offset = Immediate(i * 4);
|
||||||
|
@ -265,7 +265,7 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
|
||||||
Operation(OperationCode::UAdd, NO_PRECISE, real_address_base, it_offset);
|
Operation(OperationCode::UAdd, NO_PRECISE, real_address_base, it_offset);
|
||||||
const Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor);
|
const Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor);
|
||||||
|
|
||||||
bb.push_back(Operation(OperationCode::Assign, gmem, GetTemporal(i + 1)));
|
bb.push_back(Operation(OperationCode::Assign, gmem, GetTemporary(i + 1)));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,10 +181,10 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
|
||||||
const Node value =
|
const Node value =
|
||||||
Operation(OperationCode::TextureQueryDimensions, meta,
|
Operation(OperationCode::TextureQueryDimensions, meta,
|
||||||
GetRegister(instr.gpr8.Value() + (is_bindless ? 1 : 0)));
|
GetRegister(instr.gpr8.Value() + (is_bindless ? 1 : 0)));
|
||||||
SetTemporal(bb, indexer++, value);
|
SetTemporary(bb, indexer++, value);
|
||||||
}
|
}
|
||||||
for (u32 i = 0; i < indexer; ++i) {
|
for (u32 i = 0; i < indexer; ++i) {
|
||||||
SetRegister(bb, instr.gpr0.Value() + i, GetTemporal(i));
|
SetRegister(bb, instr.gpr0.Value() + i, GetTemporary(i));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -238,10 +238,10 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
|
||||||
auto params = coords;
|
auto params = coords;
|
||||||
MetaTexture meta{sampler, {}, {}, {}, {}, {}, {}, element};
|
MetaTexture meta{sampler, {}, {}, {}, {}, {}, {}, element};
|
||||||
const Node value = Operation(OperationCode::TextureQueryLod, meta, std::move(params));
|
const Node value = Operation(OperationCode::TextureQueryLod, meta, std::move(params));
|
||||||
SetTemporal(bb, indexer++, value);
|
SetTemporary(bb, indexer++, value);
|
||||||
}
|
}
|
||||||
for (u32 i = 0; i < indexer; ++i) {
|
for (u32 i = 0; i < indexer; ++i) {
|
||||||
SetRegister(bb, instr.gpr0.Value() + i, GetTemporal(i));
|
SetRegister(bb, instr.gpr0.Value() + i, GetTemporary(i));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -336,11 +336,11 @@ void ShaderIR::WriteTexInstructionFloat(NodeBlock& bb, Instruction instr, const
|
||||||
// Skip disabled components
|
// Skip disabled components
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SetTemporal(bb, dest_elem++, components[elem]);
|
SetTemporary(bb, dest_elem++, components[elem]);
|
||||||
}
|
}
|
||||||
// After writing values in temporals, move them to the real registers
|
// After writing values in temporals, move them to the real registers
|
||||||
for (u32 i = 0; i < dest_elem; ++i) {
|
for (u32 i = 0; i < dest_elem; ++i) {
|
||||||
SetRegister(bb, instr.gpr0.Value() + i, GetTemporal(i));
|
SetRegister(bb, instr.gpr0.Value() + i, GetTemporary(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,17 +353,17 @@ void ShaderIR::WriteTexsInstructionFloat(NodeBlock& bb, Instruction instr,
|
||||||
for (u32 component = 0; component < 4; ++component) {
|
for (u32 component = 0; component < 4; ++component) {
|
||||||
if (!instr.texs.IsComponentEnabled(component))
|
if (!instr.texs.IsComponentEnabled(component))
|
||||||
continue;
|
continue;
|
||||||
SetTemporal(bb, dest_elem++, components[component]);
|
SetTemporary(bb, dest_elem++, components[component]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 i = 0; i < dest_elem; ++i) {
|
for (u32 i = 0; i < dest_elem; ++i) {
|
||||||
if (i < 2) {
|
if (i < 2) {
|
||||||
// Write the first two swizzle components to gpr0 and gpr0+1
|
// Write the first two swizzle components to gpr0 and gpr0+1
|
||||||
SetRegister(bb, instr.gpr0.Value() + i % 2, GetTemporal(i));
|
SetRegister(bb, instr.gpr0.Value() + i % 2, GetTemporary(i));
|
||||||
} else {
|
} else {
|
||||||
ASSERT(instr.texs.HasTwoDestinations());
|
ASSERT(instr.texs.HasTwoDestinations());
|
||||||
// Write the rest of the swizzle components to gpr28 and gpr28+1
|
// Write the rest of the swizzle components to gpr28 and gpr28+1
|
||||||
SetRegister(bb, instr.gpr28.Value() + i % 2, GetTemporal(i));
|
SetRegister(bb, instr.gpr28.Value() + i % 2, GetTemporary(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -391,11 +391,11 @@ void ShaderIR::WriteTexsInstructionHalfFloat(NodeBlock& bb, Instruction instr,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetTemporal(bb, 0, first_value);
|
SetTemporary(bb, 0, first_value);
|
||||||
SetTemporal(bb, 1, Operation(OperationCode::HPack2, values[2], values[3]));
|
SetTemporary(bb, 1, Operation(OperationCode::HPack2, values[2], values[3]));
|
||||||
|
|
||||||
SetRegister(bb, instr.gpr0, GetTemporal(0));
|
SetRegister(bb, instr.gpr0, GetTemporary(0));
|
||||||
SetRegister(bb, instr.gpr28, GetTemporal(1));
|
SetRegister(bb, instr.gpr28, GetTemporary(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type,
|
Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type,
|
||||||
|
|
|
@ -73,8 +73,8 @@ u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) {
|
||||||
if (is_psl) {
|
if (is_psl) {
|
||||||
product = Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, product, Immediate(16));
|
product = Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, product, Immediate(16));
|
||||||
}
|
}
|
||||||
SetTemporal(bb, 0, product);
|
SetTemporary(bb, 0, product);
|
||||||
product = GetTemporal(0);
|
product = GetTemporary(0);
|
||||||
|
|
||||||
const Node original_c = op_c;
|
const Node original_c = op_c;
|
||||||
const Tegra::Shader::XmadMode set_mode = mode; // Workaround to clang compile error
|
const Tegra::Shader::XmadMode set_mode = mode; // Workaround to clang compile error
|
||||||
|
@ -98,13 +98,13 @@ u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) {
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
|
||||||
SetTemporal(bb, 1, op_c);
|
SetTemporary(bb, 1, op_c);
|
||||||
op_c = GetTemporal(1);
|
op_c = GetTemporary(1);
|
||||||
|
|
||||||
// TODO(Rodrigo): Use an appropiate sign for this operation
|
// TODO(Rodrigo): Use an appropiate sign for this operation
|
||||||
Node sum = Operation(OperationCode::IAdd, product, op_c);
|
Node sum = Operation(OperationCode::IAdd, product, op_c);
|
||||||
SetTemporal(bb, 2, sum);
|
SetTemporary(bb, 2, sum);
|
||||||
sum = GetTemporal(2);
|
sum = GetTemporary(2);
|
||||||
if (is_merge) {
|
if (is_merge) {
|
||||||
const Node a = BitfieldExtract(sum, 0, 16);
|
const Node a = BitfieldExtract(sum, 0, 16);
|
||||||
const Node b =
|
const Node b =
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
namespace VideoCommon::Shader {
|
namespace VideoCommon::Shader {
|
||||||
|
|
||||||
Node Conditional(Node condition, std::vector<Node> code) {
|
Node Conditional(Node condition, std::vector<Node> code) {
|
||||||
return MakeNode<ConditionalNode>(condition, std::move(code));
|
return MakeNode<ConditionalNode>(std::move(condition), std::move(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
Node Comment(std::string text) {
|
Node Comment(std::string text) {
|
||||||
|
|
|
@ -61,7 +61,7 @@ Node ShaderIR::GetConstBufferIndirect(u64 index_, u64 offset_, Node node) {
|
||||||
const auto [entry, is_new] = used_cbufs.try_emplace(index);
|
const auto [entry, is_new] = used_cbufs.try_emplace(index);
|
||||||
entry->second.MarkAsUsedIndirect();
|
entry->second.MarkAsUsedIndirect();
|
||||||
|
|
||||||
const Node final_offset = [&]() {
|
Node final_offset = [&] {
|
||||||
// Attempt to inline constant buffer without a variable offset. This is done to allow
|
// Attempt to inline constant buffer without a variable offset. This is done to allow
|
||||||
// tracking LDC calls.
|
// tracking LDC calls.
|
||||||
if (const auto gpr = std::get_if<GprNode>(&*node)) {
|
if (const auto gpr = std::get_if<GprNode>(&*node)) {
|
||||||
|
@ -69,9 +69,9 @@ Node ShaderIR::GetConstBufferIndirect(u64 index_, u64 offset_, Node node) {
|
||||||
return Immediate(offset);
|
return Immediate(offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Operation(OperationCode::UAdd, NO_PRECISE, node, Immediate(offset));
|
return Operation(OperationCode::UAdd, NO_PRECISE, std::move(node), Immediate(offset));
|
||||||
}();
|
}();
|
||||||
return MakeNode<CbufNode>(index, final_offset);
|
return MakeNode<CbufNode>(index, std::move(final_offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
Node ShaderIR::GetPredicate(u64 pred_, bool negated) {
|
Node ShaderIR::GetPredicate(u64 pred_, bool negated) {
|
||||||
|
@ -89,7 +89,7 @@ Node ShaderIR::GetPredicate(bool immediate) {
|
||||||
|
|
||||||
Node ShaderIR::GetInputAttribute(Attribute::Index index, u64 element, Node buffer) {
|
Node ShaderIR::GetInputAttribute(Attribute::Index index, u64 element, Node buffer) {
|
||||||
used_input_attributes.emplace(index);
|
used_input_attributes.emplace(index);
|
||||||
return MakeNode<AbufNode>(index, static_cast<u32>(element), buffer);
|
return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
Node ShaderIR::GetPhysicalInputAttribute(Tegra::Shader::Register physical_address, Node buffer) {
|
Node ShaderIR::GetPhysicalInputAttribute(Tegra::Shader::Register physical_address, Node buffer) {
|
||||||
|
@ -122,7 +122,7 @@ Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buff
|
||||||
}
|
}
|
||||||
used_output_attributes.insert(index);
|
used_output_attributes.insert(index);
|
||||||
|
|
||||||
return MakeNode<AbufNode>(index, static_cast<u32>(element), buffer);
|
return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) {
|
Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) {
|
||||||
|
@ -134,19 +134,19 @@ Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Node ShaderIR::GetLocalMemory(Node address) {
|
Node ShaderIR::GetLocalMemory(Node address) {
|
||||||
return MakeNode<LmemNode>(address);
|
return MakeNode<LmemNode>(std::move(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
Node ShaderIR::GetTemporal(u32 id) {
|
Node ShaderIR::GetTemporary(u32 id) {
|
||||||
return GetRegister(Register::ZeroIndex + 1 + id);
|
return GetRegister(Register::ZeroIndex + 1 + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node ShaderIR::GetOperandAbsNegFloat(Node value, bool absolute, bool negate) {
|
Node ShaderIR::GetOperandAbsNegFloat(Node value, bool absolute, bool negate) {
|
||||||
if (absolute) {
|
if (absolute) {
|
||||||
value = Operation(OperationCode::FAbsolute, NO_PRECISE, value);
|
value = Operation(OperationCode::FAbsolute, NO_PRECISE, std::move(value));
|
||||||
}
|
}
|
||||||
if (negate) {
|
if (negate) {
|
||||||
value = Operation(OperationCode::FNegate, NO_PRECISE, value);
|
value = Operation(OperationCode::FNegate, NO_PRECISE, std::move(value));
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -155,24 +155,26 @@ Node ShaderIR::GetSaturatedFloat(Node value, bool saturate) {
|
||||||
if (!saturate) {
|
if (!saturate) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
const Node positive_zero = Immediate(std::copysignf(0, 1));
|
|
||||||
const Node positive_one = Immediate(1.0f);
|
Node positive_zero = Immediate(std::copysignf(0, 1));
|
||||||
return Operation(OperationCode::FClamp, NO_PRECISE, value, positive_zero, positive_one);
|
Node positive_one = Immediate(1.0f);
|
||||||
|
return Operation(OperationCode::FClamp, NO_PRECISE, std::move(value), std::move(positive_zero),
|
||||||
|
std::move(positive_one));
|
||||||
}
|
}
|
||||||
|
|
||||||
Node ShaderIR::ConvertIntegerSize(Node value, Tegra::Shader::Register::Size size, bool is_signed) {
|
Node ShaderIR::ConvertIntegerSize(Node value, Register::Size size, bool is_signed) {
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case Register::Size::Byte:
|
case Register::Size::Byte:
|
||||||
value = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed, NO_PRECISE, value,
|
value = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed, NO_PRECISE,
|
||||||
Immediate(24));
|
std::move(value), Immediate(24));
|
||||||
value = SignedOperation(OperationCode::IArithmeticShiftRight, is_signed, NO_PRECISE, value,
|
value = SignedOperation(OperationCode::IArithmeticShiftRight, is_signed, NO_PRECISE,
|
||||||
Immediate(24));
|
std::move(value), Immediate(24));
|
||||||
return value;
|
return value;
|
||||||
case Register::Size::Short:
|
case Register::Size::Short:
|
||||||
value = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed, NO_PRECISE, value,
|
value = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed, NO_PRECISE,
|
||||||
Immediate(16));
|
std::move(value), Immediate(16));
|
||||||
value = SignedOperation(OperationCode::IArithmeticShiftRight, is_signed, NO_PRECISE, value,
|
value = SignedOperation(OperationCode::IArithmeticShiftRight, is_signed, NO_PRECISE,
|
||||||
Immediate(16));
|
std::move(value), Immediate(16));
|
||||||
case Register::Size::Word:
|
case Register::Size::Word:
|
||||||
// Default - do nothing
|
// Default - do nothing
|
||||||
return value;
|
return value;
|
||||||
|
@ -188,27 +190,29 @@ Node ShaderIR::GetOperandAbsNegInteger(Node value, bool absolute, bool negate, b
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
if (absolute) {
|
if (absolute) {
|
||||||
value = Operation(OperationCode::IAbsolute, NO_PRECISE, value);
|
value = Operation(OperationCode::IAbsolute, NO_PRECISE, std::move(value));
|
||||||
}
|
}
|
||||||
if (negate) {
|
if (negate) {
|
||||||
value = Operation(OperationCode::INegate, NO_PRECISE, value);
|
value = Operation(OperationCode::INegate, NO_PRECISE, std::move(value));
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node ShaderIR::UnpackHalfImmediate(Instruction instr, bool has_negation) {
|
Node ShaderIR::UnpackHalfImmediate(Instruction instr, bool has_negation) {
|
||||||
const Node value = Immediate(instr.half_imm.PackImmediates());
|
Node value = Immediate(instr.half_imm.PackImmediates());
|
||||||
if (!has_negation) {
|
if (!has_negation) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
const Node first_negate = GetPredicate(instr.half_imm.first_negate != 0);
|
|
||||||
const Node second_negate = GetPredicate(instr.half_imm.second_negate != 0);
|
|
||||||
|
|
||||||
return Operation(OperationCode::HNegate, NO_PRECISE, value, first_negate, second_negate);
|
Node first_negate = GetPredicate(instr.half_imm.first_negate != 0);
|
||||||
|
Node second_negate = GetPredicate(instr.half_imm.second_negate != 0);
|
||||||
|
|
||||||
|
return Operation(OperationCode::HNegate, NO_PRECISE, std::move(value), std::move(first_negate),
|
||||||
|
std::move(second_negate));
|
||||||
}
|
}
|
||||||
|
|
||||||
Node ShaderIR::UnpackHalfFloat(Node value, Tegra::Shader::HalfType type) {
|
Node ShaderIR::UnpackHalfFloat(Node value, Tegra::Shader::HalfType type) {
|
||||||
return Operation(OperationCode::HUnpack, type, value);
|
return Operation(OperationCode::HUnpack, type, std::move(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
Node ShaderIR::HalfMerge(Node dest, Node src, Tegra::Shader::HalfMerge merge) {
|
Node ShaderIR::HalfMerge(Node dest, Node src, Tegra::Shader::HalfMerge merge) {
|
||||||
|
@ -216,11 +220,11 @@ Node ShaderIR::HalfMerge(Node dest, Node src, Tegra::Shader::HalfMerge merge) {
|
||||||
case Tegra::Shader::HalfMerge::H0_H1:
|
case Tegra::Shader::HalfMerge::H0_H1:
|
||||||
return src;
|
return src;
|
||||||
case Tegra::Shader::HalfMerge::F32:
|
case Tegra::Shader::HalfMerge::F32:
|
||||||
return Operation(OperationCode::HMergeF32, src);
|
return Operation(OperationCode::HMergeF32, std::move(src));
|
||||||
case Tegra::Shader::HalfMerge::Mrg_H0:
|
case Tegra::Shader::HalfMerge::Mrg_H0:
|
||||||
return Operation(OperationCode::HMergeH0, dest, src);
|
return Operation(OperationCode::HMergeH0, std::move(dest), std::move(src));
|
||||||
case Tegra::Shader::HalfMerge::Mrg_H1:
|
case Tegra::Shader::HalfMerge::Mrg_H1:
|
||||||
return Operation(OperationCode::HMergeH1, dest, src);
|
return Operation(OperationCode::HMergeH1, std::move(dest), std::move(src));
|
||||||
}
|
}
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
return src;
|
return src;
|
||||||
|
@ -228,10 +232,10 @@ Node ShaderIR::HalfMerge(Node dest, Node src, Tegra::Shader::HalfMerge merge) {
|
||||||
|
|
||||||
Node ShaderIR::GetOperandAbsNegHalf(Node value, bool absolute, bool negate) {
|
Node ShaderIR::GetOperandAbsNegHalf(Node value, bool absolute, bool negate) {
|
||||||
if (absolute) {
|
if (absolute) {
|
||||||
value = Operation(OperationCode::HAbsolute, NO_PRECISE, value);
|
value = Operation(OperationCode::HAbsolute, NO_PRECISE, std::move(value));
|
||||||
}
|
}
|
||||||
if (negate) {
|
if (negate) {
|
||||||
value = Operation(OperationCode::HNegate, NO_PRECISE, value, GetPredicate(true),
|
value = Operation(OperationCode::HNegate, NO_PRECISE, std::move(value), GetPredicate(true),
|
||||||
GetPredicate(true));
|
GetPredicate(true));
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
|
@ -241,9 +245,11 @@ Node ShaderIR::GetSaturatedHalfFloat(Node value, bool saturate) {
|
||||||
if (!saturate) {
|
if (!saturate) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
const Node positive_zero = Immediate(std::copysignf(0, 1));
|
|
||||||
const Node positive_one = Immediate(1.0f);
|
Node positive_zero = Immediate(std::copysignf(0, 1));
|
||||||
return Operation(OperationCode::HClamp, NO_PRECISE, value, positive_zero, positive_one);
|
Node positive_one = Immediate(1.0f);
|
||||||
|
return Operation(OperationCode::HClamp, NO_PRECISE, std::move(value), std::move(positive_zero),
|
||||||
|
std::move(positive_one));
|
||||||
}
|
}
|
||||||
|
|
||||||
Node ShaderIR::GetPredicateComparisonFloat(PredCondition condition, Node op_a, Node op_b) {
|
Node ShaderIR::GetPredicateComparisonFloat(PredCondition condition, Node op_a, Node op_b) {
|
||||||
|
@ -271,7 +277,6 @@ Node ShaderIR::GetPredicateComparisonFloat(PredCondition condition, Node op_a, N
|
||||||
condition == PredCondition::LessEqualWithNan ||
|
condition == PredCondition::LessEqualWithNan ||
|
||||||
condition == PredCondition::GreaterThanWithNan ||
|
condition == PredCondition::GreaterThanWithNan ||
|
||||||
condition == PredCondition::GreaterEqualWithNan) {
|
condition == PredCondition::GreaterEqualWithNan) {
|
||||||
|
|
||||||
predicate = Operation(OperationCode::LogicalOr, predicate,
|
predicate = Operation(OperationCode::LogicalOr, predicate,
|
||||||
Operation(OperationCode::LogicalFIsNan, op_a));
|
Operation(OperationCode::LogicalFIsNan, op_a));
|
||||||
predicate = Operation(OperationCode::LogicalOr, predicate,
|
predicate = Operation(OperationCode::LogicalOr, predicate,
|
||||||
|
@ -300,7 +305,8 @@ Node ShaderIR::GetPredicateComparisonInteger(PredCondition condition, bool is_si
|
||||||
UNIMPLEMENTED_IF_MSG(comparison == PredicateComparisonTable.end(),
|
UNIMPLEMENTED_IF_MSG(comparison == PredicateComparisonTable.end(),
|
||||||
"Unknown predicate comparison operation");
|
"Unknown predicate comparison operation");
|
||||||
|
|
||||||
Node predicate = SignedOperation(comparison->second, is_signed, NO_PRECISE, op_a, op_b);
|
Node predicate = SignedOperation(comparison->second, is_signed, NO_PRECISE, std::move(op_a),
|
||||||
|
std::move(op_b));
|
||||||
|
|
||||||
UNIMPLEMENTED_IF_MSG(condition == PredCondition::LessThanWithNan ||
|
UNIMPLEMENTED_IF_MSG(condition == PredCondition::LessThanWithNan ||
|
||||||
condition == PredCondition::NotEqualWithNan ||
|
condition == PredCondition::NotEqualWithNan ||
|
||||||
|
@ -330,9 +336,7 @@ Node ShaderIR::GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition
|
||||||
UNIMPLEMENTED_IF_MSG(comparison == PredicateComparisonTable.end(),
|
UNIMPLEMENTED_IF_MSG(comparison == PredicateComparisonTable.end(),
|
||||||
"Unknown predicate comparison operation");
|
"Unknown predicate comparison operation");
|
||||||
|
|
||||||
const Node predicate = Operation(comparison->second, NO_PRECISE, op_a, op_b);
|
return Operation(comparison->second, NO_PRECISE, std::move(op_a), std::move(op_b));
|
||||||
|
|
||||||
return predicate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OperationCode ShaderIR::GetPredicateCombiner(PredOperation operation) {
|
OperationCode ShaderIR::GetPredicateCombiner(PredOperation operation) {
|
||||||
|
@ -358,31 +362,32 @@ Node ShaderIR::GetConditionCode(Tegra::Shader::ConditionCode cc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderIR::SetRegister(NodeBlock& bb, Register dest, Node src) {
|
void ShaderIR::SetRegister(NodeBlock& bb, Register dest, Node src) {
|
||||||
bb.push_back(Operation(OperationCode::Assign, GetRegister(dest), src));
|
bb.push_back(Operation(OperationCode::Assign, GetRegister(dest), std::move(src)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderIR::SetPredicate(NodeBlock& bb, u64 dest, Node src) {
|
void ShaderIR::SetPredicate(NodeBlock& bb, u64 dest, Node src) {
|
||||||
bb.push_back(Operation(OperationCode::LogicalAssign, GetPredicate(dest), src));
|
bb.push_back(Operation(OperationCode::LogicalAssign, GetPredicate(dest), std::move(src)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderIR::SetInternalFlag(NodeBlock& bb, InternalFlag flag, Node value) {
|
void ShaderIR::SetInternalFlag(NodeBlock& bb, InternalFlag flag, Node value) {
|
||||||
bb.push_back(Operation(OperationCode::LogicalAssign, GetInternalFlag(flag), value));
|
bb.push_back(Operation(OperationCode::LogicalAssign, GetInternalFlag(flag), std::move(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderIR::SetLocalMemory(NodeBlock& bb, Node address, Node value) {
|
void ShaderIR::SetLocalMemory(NodeBlock& bb, Node address, Node value) {
|
||||||
bb.push_back(Operation(OperationCode::Assign, GetLocalMemory(address), value));
|
bb.push_back(
|
||||||
|
Operation(OperationCode::Assign, GetLocalMemory(std::move(address)), std::move(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderIR::SetTemporal(NodeBlock& bb, u32 id, Node value) {
|
void ShaderIR::SetTemporary(NodeBlock& bb, u32 id, Node value) {
|
||||||
SetRegister(bb, Register::ZeroIndex + 1 + id, value);
|
SetRegister(bb, Register::ZeroIndex + 1 + id, std::move(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderIR::SetInternalFlagsFromFloat(NodeBlock& bb, Node value, bool sets_cc) {
|
void ShaderIR::SetInternalFlagsFromFloat(NodeBlock& bb, Node value, bool sets_cc) {
|
||||||
if (!sets_cc) {
|
if (!sets_cc) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const Node zerop = Operation(OperationCode::LogicalFEqual, value, Immediate(0.0f));
|
Node zerop = Operation(OperationCode::LogicalFEqual, std::move(value), Immediate(0.0f));
|
||||||
SetInternalFlag(bb, InternalFlag::Zero, zerop);
|
SetInternalFlag(bb, InternalFlag::Zero, std::move(zerop));
|
||||||
LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete");
|
LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,14 +395,14 @@ void ShaderIR::SetInternalFlagsFromInteger(NodeBlock& bb, Node value, bool sets_
|
||||||
if (!sets_cc) {
|
if (!sets_cc) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const Node zerop = Operation(OperationCode::LogicalIEqual, value, Immediate(0));
|
Node zerop = Operation(OperationCode::LogicalIEqual, std::move(value), Immediate(0));
|
||||||
SetInternalFlag(bb, InternalFlag::Zero, zerop);
|
SetInternalFlag(bb, InternalFlag::Zero, std::move(zerop));
|
||||||
LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete");
|
LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete");
|
||||||
}
|
}
|
||||||
|
|
||||||
Node ShaderIR::BitfieldExtract(Node value, u32 offset, u32 bits) {
|
Node ShaderIR::BitfieldExtract(Node value, u32 offset, u32 bits) {
|
||||||
return Operation(OperationCode::UBitfieldExtract, NO_PRECISE, value, Immediate(offset),
|
return Operation(OperationCode::UBitfieldExtract, NO_PRECISE, std::move(value),
|
||||||
Immediate(bits));
|
Immediate(offset), Immediate(bits));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace VideoCommon::Shader
|
} // namespace VideoCommon::Shader
|
||||||
|
|
|
@ -5,13 +5,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstring>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <variant>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
@ -210,8 +207,8 @@ private:
|
||||||
Node GetInternalFlag(InternalFlag flag, bool negated = false);
|
Node GetInternalFlag(InternalFlag flag, bool negated = false);
|
||||||
/// Generates a node representing a local memory address
|
/// Generates a node representing a local memory address
|
||||||
Node GetLocalMemory(Node address);
|
Node GetLocalMemory(Node address);
|
||||||
/// Generates a temporal, internally it uses a post-RZ register
|
/// Generates a temporary, internally it uses a post-RZ register
|
||||||
Node GetTemporal(u32 id);
|
Node GetTemporary(u32 id);
|
||||||
|
|
||||||
/// Sets a register. src value must be a number-evaluated node.
|
/// Sets a register. src value must be a number-evaluated node.
|
||||||
void SetRegister(NodeBlock& bb, Tegra::Shader::Register dest, Node src);
|
void SetRegister(NodeBlock& bb, Tegra::Shader::Register dest, Node src);
|
||||||
|
@ -221,8 +218,8 @@ private:
|
||||||
void SetInternalFlag(NodeBlock& bb, InternalFlag flag, Node value);
|
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. address and value must be a number-evaluated node
|
||||||
void SetLocalMemory(NodeBlock& bb, Node address, Node value);
|
void SetLocalMemory(NodeBlock& bb, Node address, Node value);
|
||||||
/// Sets a temporal. Internally it uses a post-RZ register
|
/// Sets a temporary. Internally it uses a post-RZ register
|
||||||
void SetTemporal(NodeBlock& bb, u32 id, Node value);
|
void SetTemporary(NodeBlock& bb, u32 id, Node value);
|
||||||
|
|
||||||
/// Sets internal flags from a float
|
/// Sets internal flags from a float
|
||||||
void SetInternalFlagsFromFloat(NodeBlock& bb, Node value, bool sets_cc = true);
|
void SetInternalFlagsFromFloat(NodeBlock& bb, Node value, bool sets_cc = true);
|
||||||
|
|
|
@ -15,18 +15,20 @@ namespace {
|
||||||
std::pair<Node, s64> FindOperation(const NodeBlock& code, s64 cursor,
|
std::pair<Node, s64> FindOperation(const NodeBlock& code, s64 cursor,
|
||||||
OperationCode operation_code) {
|
OperationCode operation_code) {
|
||||||
for (; cursor >= 0; --cursor) {
|
for (; cursor >= 0; --cursor) {
|
||||||
const Node node = code.at(cursor);
|
Node node = code.at(cursor);
|
||||||
|
|
||||||
if (const auto operation = std::get_if<OperationNode>(&*node)) {
|
if (const auto operation = std::get_if<OperationNode>(&*node)) {
|
||||||
if (operation->GetCode() == operation_code) {
|
if (operation->GetCode() == operation_code) {
|
||||||
return {node, cursor};
|
return {std::move(node), cursor};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto conditional = std::get_if<ConditionalNode>(&*node)) {
|
if (const auto conditional = std::get_if<ConditionalNode>(&*node)) {
|
||||||
const auto& conditional_code = conditional->GetCode();
|
const auto& conditional_code = conditional->GetCode();
|
||||||
const auto [found, internal_cursor] = FindOperation(
|
auto [found, internal_cursor] = FindOperation(
|
||||||
conditional_code, static_cast<s64>(conditional_code.size() - 1), operation_code);
|
conditional_code, static_cast<s64>(conditional_code.size() - 1), operation_code);
|
||||||
if (found) {
|
if (found) {
|
||||||
return {found, cursor};
|
return {std::move(found), cursor};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue