xmad.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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,
  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;
  61. op_b = SignedOperation(OperationCode::IBitfieldExtract, is_signed_b, std::move(op_b),
  62. is_high_b ? Immediate(16) : Immediate(0), Immediate(16));
  63. // we already check sign_a and sign_b is difference or not before so just use one in here.
  64. Node product = SignedOperation(OperationCode::IMul, is_signed_a, op_a, op_b);
  65. if (is_psl) {
  66. product =
  67. SignedOperation(OperationCode::ILogicalShiftLeft, is_signed_a, product, Immediate(16));
  68. }
  69. SetTemporary(bb, 0, product);
  70. product = GetTemporary(0);
  71. const Node original_c = op_c;
  72. const Tegra::Shader::XmadMode set_mode = mode; // Workaround to clang compile error
  73. op_c = [&]() {
  74. switch (set_mode) {
  75. case Tegra::Shader::XmadMode::None:
  76. return original_c;
  77. case Tegra::Shader::XmadMode::CLo:
  78. return BitfieldExtract(original_c, 0, 16);
  79. case Tegra::Shader::XmadMode::CHi:
  80. return BitfieldExtract(original_c, 16, 16);
  81. case Tegra::Shader::XmadMode::CBcc: {
  82. const Node shifted_b = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed_b,
  83. original_b, Immediate(16));
  84. return SignedOperation(OperationCode::IAdd, is_signed_c, original_c, shifted_b);
  85. }
  86. case Tegra::Shader::XmadMode::CSfu: {
  87. const Node comp_a = GetPredicateComparisonInteger(PredCondition::Equal, is_signed_a,
  88. op_a, Immediate(0));
  89. const Node comp_b = GetPredicateComparisonInteger(PredCondition::Equal, is_signed_b,
  90. op_b, Immediate(0));
  91. const Node comp =
  92. Operation(OperationCode::LogicalOr, std::move(comp_a), std::move(comp_b));
  93. const Node comp_minus_a = GetPredicateComparisonInteger(
  94. PredCondition::NotEqual, is_signed_a,
  95. SignedOperation(OperationCode::IBitwiseAnd, is_signed_a, op_a,
  96. Immediate(0x80000000)),
  97. Immediate(0));
  98. const Node comp_minus_b = GetPredicateComparisonInteger(
  99. PredCondition::NotEqual, is_signed_b,
  100. SignedOperation(OperationCode::IBitwiseAnd, is_signed_b, op_b,
  101. Immediate(0x80000000)),
  102. Immediate(0));
  103. Node new_c = Operation(
  104. OperationCode::Select, comp_minus_a,
  105. SignedOperation(OperationCode::IAdd, is_signed_c, original_c, Immediate(-65536)),
  106. original_c);
  107. new_c = Operation(
  108. OperationCode::Select, comp_minus_b,
  109. SignedOperation(OperationCode::IAdd, is_signed_c, new_c, Immediate(-65536)), new_c);
  110. return Operation(OperationCode::Select, comp, original_c, new_c);
  111. }
  112. default:
  113. UNREACHABLE();
  114. return Immediate(0);
  115. }
  116. }();
  117. SetTemporary(bb, 1, op_c);
  118. op_c = GetTemporary(1);
  119. // TODO(Rodrigo): Use an appropiate sign for this operation
  120. Node sum = Operation(OperationCode::IAdd, product, op_c);
  121. SetTemporary(bb, 2, sum);
  122. sum = GetTemporary(2);
  123. if (is_merge) {
  124. const Node a = BitfieldExtract(sum, 0, 16);
  125. const Node b =
  126. Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, original_b, Immediate(16));
  127. sum = Operation(OperationCode::IBitwiseOr, NO_PRECISE, a, b);
  128. }
  129. SetInternalFlagsFromInteger(bb, sum, instr.generates_cc);
  130. SetRegister(bb, instr.gpr0, sum);
  131. return pc;
  132. }
  133. } // namespace VideoCommon::Shader