xmad.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. // Copyright 2018 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/assert.h"
  5. #include "common/common_types.h"
  6. #include "video_core/engines/shader_bytecode.h"
  7. #include "video_core/shader/node_helper.h"
  8. #include "video_core/shader/shader_ir.h"
  9. namespace VideoCommon::Shader {
  10. using Tegra::Shader::Instruction;
  11. using Tegra::Shader::OpCode;
  12. using Tegra::Shader::PredCondition;
  13. u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) {
  14. const Instruction instr = {program_code[pc]};
  15. const auto opcode = OpCode::Decode(instr);
  16. UNIMPLEMENTED_IF(instr.xmad.sign_a);
  17. UNIMPLEMENTED_IF(instr.xmad.sign_b);
  18. UNIMPLEMENTED_IF_MSG(instr.generates_cc,
  19. "Condition codes generation in XMAD is not implemented");
  20. Node op_a = GetRegister(instr.gpr8);
  21. // TODO(bunnei): Needs to be fixed once op_a or op_b is signed
  22. UNIMPLEMENTED_IF(instr.xmad.sign_a != instr.xmad.sign_b);
  23. const bool is_signed_a = instr.xmad.sign_a == 1;
  24. const bool is_signed_b = instr.xmad.sign_b == 1;
  25. const bool is_signed_c = is_signed_a;
  26. auto [is_merge, is_psl, is_high_b, mode, op_b_binding,
  27. op_c] = [&]() -> std::tuple<bool, bool, bool, Tegra::Shader::XmadMode, Node, Node> {
  28. switch (opcode->get().GetId()) {
  29. case OpCode::Id::XMAD_CR:
  30. return {instr.xmad.merge_56,
  31. instr.xmad.product_shift_left_second,
  32. instr.xmad.high_b,
  33. instr.xmad.mode_cbf,
  34. GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()),
  35. GetRegister(instr.gpr39)};
  36. case OpCode::Id::XMAD_RR:
  37. return {instr.xmad.merge_37, instr.xmad.product_shift_left, instr.xmad.high_b_rr,
  38. instr.xmad.mode, GetRegister(instr.gpr20), GetRegister(instr.gpr39)};
  39. case OpCode::Id::XMAD_RC:
  40. return {false,
  41. false,
  42. instr.xmad.high_b,
  43. instr.xmad.mode_cbf,
  44. GetRegister(instr.gpr39),
  45. GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset())};
  46. case OpCode::Id::XMAD_IMM:
  47. return {instr.xmad.merge_37,
  48. instr.xmad.product_shift_left,
  49. false,
  50. instr.xmad.mode,
  51. Immediate(static_cast<u32>(instr.xmad.imm20_16)),
  52. GetRegister(instr.gpr39)};
  53. default:
  54. UNIMPLEMENTED_MSG("Unhandled XMAD instruction: {}", opcode->get().GetName());
  55. return {false, false, false, Tegra::Shader::XmadMode::None, Immediate(0), Immediate(0)};
  56. }
  57. }();
  58. op_a = SignedOperation(OperationCode::IBitfieldExtract, is_signed_a, std::move(op_a),
  59. instr.xmad.high_a ? Immediate(16) : Immediate(0), Immediate(16));
  60. const Node original_b = op_b_binding;
  61. const Node op_b =
  62. SignedOperation(OperationCode::IBitfieldExtract, is_signed_b, std::move(op_b_binding),
  63. is_high_b ? Immediate(16) : Immediate(0), Immediate(16));
  64. // we already check sign_a and sign_b is difference or not before so just use one in here.
  65. Node product = SignedOperation(OperationCode::IMul, is_signed_a, op_a, op_b);
  66. if (is_psl) {
  67. product =
  68. SignedOperation(OperationCode::ILogicalShiftLeft, is_signed_a, product, Immediate(16));
  69. }
  70. SetTemporary(bb, 0, product);
  71. product = GetTemporary(0);
  72. Node original_c = op_c;
  73. const Tegra::Shader::XmadMode set_mode = mode; // Workaround to clang compile error
  74. op_c = [&] {
  75. switch (set_mode) {
  76. case Tegra::Shader::XmadMode::None:
  77. return original_c;
  78. case Tegra::Shader::XmadMode::CLo:
  79. return BitfieldExtract(std::move(original_c), 0, 16);
  80. case Tegra::Shader::XmadMode::CHi:
  81. return BitfieldExtract(std::move(original_c), 16, 16);
  82. case Tegra::Shader::XmadMode::CBcc: {
  83. Node shifted_b = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed_b,
  84. original_b, Immediate(16));
  85. return SignedOperation(OperationCode::IAdd, is_signed_c, std::move(original_c),
  86. std::move(shifted_b));
  87. }
  88. case Tegra::Shader::XmadMode::CSfu: {
  89. const Node comp_a =
  90. GetPredicateComparisonInteger(PredCondition::EQ, is_signed_a, op_a, Immediate(0));
  91. const Node comp_b =
  92. GetPredicateComparisonInteger(PredCondition::EQ, is_signed_b, op_b, Immediate(0));
  93. const Node comp = Operation(OperationCode::LogicalOr, comp_a, comp_b);
  94. const Node comp_minus_a = GetPredicateComparisonInteger(
  95. PredCondition::NE, is_signed_a,
  96. SignedOperation(OperationCode::IBitwiseAnd, is_signed_a, op_a,
  97. Immediate(0x80000000)),
  98. Immediate(0));
  99. const Node comp_minus_b = GetPredicateComparisonInteger(
  100. PredCondition::NE, is_signed_b,
  101. SignedOperation(OperationCode::IBitwiseAnd, is_signed_b, op_b,
  102. Immediate(0x80000000)),
  103. Immediate(0));
  104. Node new_c = Operation(
  105. OperationCode::Select, comp_minus_a,
  106. SignedOperation(OperationCode::IAdd, is_signed_c, original_c, Immediate(-65536)),
  107. original_c);
  108. new_c = Operation(
  109. OperationCode::Select, comp_minus_b,
  110. SignedOperation(OperationCode::IAdd, is_signed_c, new_c, Immediate(-65536)),
  111. std::move(new_c));
  112. return Operation(OperationCode::Select, comp, original_c, std::move(new_c));
  113. }
  114. default:
  115. UNREACHABLE();
  116. return Immediate(0);
  117. }
  118. }();
  119. SetTemporary(bb, 1, op_c);
  120. op_c = GetTemporary(1);
  121. // TODO(Rodrigo): Use an appropiate sign for this operation
  122. Node sum = SignedOperation(OperationCode::IAdd, is_signed_a, product, std::move(op_c));
  123. SetTemporary(bb, 2, sum);
  124. sum = GetTemporary(2);
  125. if (is_merge) {
  126. const Node a = SignedOperation(OperationCode::IBitfieldExtract, is_signed_a, std::move(sum),
  127. Immediate(0), Immediate(16));
  128. const Node b = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed_b, original_b,
  129. Immediate(16));
  130. sum = SignedOperation(OperationCode::IBitwiseOr, is_signed_a, a, b);
  131. }
  132. SetInternalFlagsFromInteger(bb, sum, instr.generates_cc);
  133. SetRegister(bb, instr.gpr0, std::move(sum));
  134. return pc;
  135. }
  136. } // namespace VideoCommon::Shader