arithmetic.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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 "common/logging/log.h"
  7. #include "video_core/engines/shader_bytecode.h"
  8. #include "video_core/shader/node_helper.h"
  9. #include "video_core/shader/shader_ir.h"
  10. namespace VideoCommon::Shader {
  11. using Tegra::Shader::Instruction;
  12. using Tegra::Shader::OpCode;
  13. using Tegra::Shader::SubOp;
  14. u32 ShaderIR::DecodeArithmetic(NodeBlock& bb, u32 pc) {
  15. const Instruction instr = {program_code[pc]};
  16. const auto opcode = OpCode::Decode(instr);
  17. Node op_a = GetRegister(instr.gpr8);
  18. Node op_b = [&]() -> Node {
  19. if (instr.is_b_imm) {
  20. return GetImmediate19(instr);
  21. } else if (instr.is_b_gpr) {
  22. return GetRegister(instr.gpr20);
  23. } else {
  24. return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset());
  25. }
  26. }();
  27. switch (opcode->get().GetId()) {
  28. case OpCode::Id::MOV_C:
  29. case OpCode::Id::MOV_R: {
  30. // MOV does not have neither 'abs' nor 'neg' bits.
  31. SetRegister(bb, instr.gpr0, op_b);
  32. break;
  33. }
  34. case OpCode::Id::FMUL_C:
  35. case OpCode::Id::FMUL_R:
  36. case OpCode::Id::FMUL_IMM: {
  37. // FMUL does not have 'abs' bits and only the second operand has a 'neg' bit.
  38. if (instr.fmul.tab5cb8_2 != 0) {
  39. LOG_DEBUG(HW_GPU, "FMUL tab5cb8_2({}) is not implemented",
  40. instr.fmul.tab5cb8_2.Value());
  41. }
  42. if (instr.fmul.tab5c68_0 != 1) {
  43. LOG_DEBUG(HW_GPU, "FMUL tab5cb8_0({}) is not implemented",
  44. instr.fmul.tab5c68_0.Value());
  45. }
  46. op_b = GetOperandAbsNegFloat(op_b, false, instr.fmul.negate_b);
  47. // TODO(Rodrigo): Should precise be used when there's a postfactor?
  48. Node value = Operation(OperationCode::FMul, PRECISE, op_a, op_b);
  49. if (instr.fmul.postfactor != 0) {
  50. auto postfactor = static_cast<s32>(instr.fmul.postfactor);
  51. // Postfactor encoded as 3-bit 1's complement in instruction, interpreted with below
  52. // logic.
  53. if (postfactor >= 4) {
  54. postfactor = 7 - postfactor;
  55. } else {
  56. postfactor = 0 - postfactor;
  57. }
  58. if (postfactor > 0) {
  59. value = Operation(OperationCode::FMul, NO_PRECISE, value,
  60. Immediate(static_cast<f32>(1 << postfactor)));
  61. } else {
  62. value = Operation(OperationCode::FDiv, NO_PRECISE, value,
  63. Immediate(static_cast<f32>(1 << -postfactor)));
  64. }
  65. }
  66. value = GetSaturatedFloat(value, instr.alu.saturate_d);
  67. SetInternalFlagsFromFloat(bb, value, instr.generates_cc);
  68. SetRegister(bb, instr.gpr0, value);
  69. break;
  70. }
  71. case OpCode::Id::FADD_C:
  72. case OpCode::Id::FADD_R:
  73. case OpCode::Id::FADD_IMM: {
  74. op_a = GetOperandAbsNegFloat(op_a, instr.alu.abs_a, instr.alu.negate_a);
  75. op_b = GetOperandAbsNegFloat(op_b, instr.alu.abs_b, instr.alu.negate_b);
  76. Node value = Operation(OperationCode::FAdd, PRECISE, op_a, op_b);
  77. value = GetSaturatedFloat(value, instr.alu.saturate_d);
  78. SetInternalFlagsFromFloat(bb, value, instr.generates_cc);
  79. SetRegister(bb, instr.gpr0, value);
  80. break;
  81. }
  82. case OpCode::Id::MUFU: {
  83. op_a = GetOperandAbsNegFloat(op_a, instr.alu.abs_a, instr.alu.negate_a);
  84. Node value = [&]() {
  85. switch (instr.sub_op) {
  86. case SubOp::Cos:
  87. return Operation(OperationCode::FCos, PRECISE, op_a);
  88. case SubOp::Sin:
  89. return Operation(OperationCode::FSin, PRECISE, op_a);
  90. case SubOp::Ex2:
  91. return Operation(OperationCode::FExp2, PRECISE, op_a);
  92. case SubOp::Lg2:
  93. return Operation(OperationCode::FLog2, PRECISE, op_a);
  94. case SubOp::Rcp:
  95. return Operation(OperationCode::FDiv, PRECISE, Immediate(1.0f), op_a);
  96. case SubOp::Rsq:
  97. return Operation(OperationCode::FInverseSqrt, PRECISE, op_a);
  98. case SubOp::Sqrt:
  99. return Operation(OperationCode::FSqrt, PRECISE, op_a);
  100. default:
  101. UNIMPLEMENTED_MSG("Unhandled MUFU sub op={0:x}",
  102. static_cast<unsigned>(instr.sub_op.Value()));
  103. return Immediate(0);
  104. }
  105. }();
  106. value = GetSaturatedFloat(value, instr.alu.saturate_d);
  107. SetRegister(bb, instr.gpr0, value);
  108. break;
  109. }
  110. case OpCode::Id::FMNMX_C:
  111. case OpCode::Id::FMNMX_R:
  112. case OpCode::Id::FMNMX_IMM: {
  113. op_a = GetOperandAbsNegFloat(op_a, instr.alu.abs_a, instr.alu.negate_a);
  114. op_b = GetOperandAbsNegFloat(op_b, instr.alu.abs_b, instr.alu.negate_b);
  115. const Node condition = GetPredicate(instr.alu.fmnmx.pred, instr.alu.fmnmx.negate_pred != 0);
  116. const Node min = Operation(OperationCode::FMin, NO_PRECISE, op_a, op_b);
  117. const Node max = Operation(OperationCode::FMax, NO_PRECISE, op_a, op_b);
  118. const Node value = Operation(OperationCode::Select, NO_PRECISE, condition, min, max);
  119. SetInternalFlagsFromFloat(bb, value, instr.generates_cc);
  120. SetRegister(bb, instr.gpr0, value);
  121. break;
  122. }
  123. case OpCode::Id::RRO_C:
  124. case OpCode::Id::RRO_R:
  125. case OpCode::Id::RRO_IMM: {
  126. LOG_DEBUG(HW_GPU, "(STUBBED) RRO used");
  127. // Currently RRO is only implemented as a register move.
  128. op_b = GetOperandAbsNegFloat(op_b, instr.alu.abs_b, instr.alu.negate_b);
  129. SetRegister(bb, instr.gpr0, op_b);
  130. break;
  131. }
  132. default:
  133. UNIMPLEMENTED_MSG("Unhandled arithmetic instruction: {}", opcode->get().GetName());
  134. }
  135. return pc;
  136. }
  137. } // namespace VideoCommon::Shader