conversion.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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/shader_ir.h"
  8. namespace VideoCommon::Shader {
  9. using Tegra::Shader::Instruction;
  10. using Tegra::Shader::OpCode;
  11. using Tegra::Shader::Register;
  12. u32 ShaderIR::DecodeConversion(BasicBlock& bb, u32 pc) {
  13. const Instruction instr = {program_code[pc]};
  14. const auto opcode = OpCode::Decode(instr);
  15. switch (opcode->get().GetId()) {
  16. case OpCode::Id::I2I_R: {
  17. UNIMPLEMENTED_IF(instr.conversion.selector);
  18. const bool input_signed = instr.conversion.is_input_signed;
  19. const bool output_signed = instr.conversion.is_output_signed;
  20. Node value = GetRegister(instr.gpr20);
  21. value = ConvertIntegerSize(value, instr.conversion.src_size, input_signed);
  22. value = GetOperandAbsNegInteger(value, instr.conversion.abs_a, instr.conversion.negate_a,
  23. input_signed);
  24. if (input_signed != output_signed) {
  25. value = SignedOperation(OperationCode::ICastUnsigned, output_signed, NO_PRECISE, value);
  26. }
  27. SetInternalFlagsFromInteger(bb, value, instr.generates_cc);
  28. SetRegister(bb, instr.gpr0, value);
  29. break;
  30. }
  31. case OpCode::Id::I2F_R:
  32. case OpCode::Id::I2F_C: {
  33. UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word);
  34. UNIMPLEMENTED_IF(instr.conversion.selector);
  35. UNIMPLEMENTED_IF_MSG(instr.generates_cc,
  36. "Condition codes generation in I2F is not implemented");
  37. Node value = [&]() {
  38. if (instr.is_b_gpr) {
  39. return GetRegister(instr.gpr20);
  40. } else {
  41. return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.offset);
  42. }
  43. }();
  44. const bool input_signed = instr.conversion.is_input_signed;
  45. value = ConvertIntegerSize(value, instr.conversion.src_size, input_signed);
  46. value = GetOperandAbsNegInteger(value, instr.conversion.abs_a, false, input_signed);
  47. value = SignedOperation(OperationCode::FCastInteger, input_signed, PRECISE, value);
  48. value = GetOperandAbsNegFloat(value, false, instr.conversion.negate_a);
  49. SetInternalFlagsFromFloat(bb, value, instr.generates_cc);
  50. SetRegister(bb, instr.gpr0, value);
  51. break;
  52. }
  53. case OpCode::Id::F2F_R:
  54. case OpCode::Id::F2F_C: {
  55. UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word);
  56. UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word);
  57. UNIMPLEMENTED_IF_MSG(instr.generates_cc,
  58. "Condition codes generation in F2F is not implemented");
  59. Node value = [&]() {
  60. if (instr.is_b_gpr) {
  61. return GetRegister(instr.gpr20);
  62. } else {
  63. return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.offset);
  64. }
  65. }();
  66. value = GetOperandAbsNegFloat(value, instr.conversion.abs_a, instr.conversion.negate_a);
  67. value = [&]() {
  68. switch (instr.conversion.f2f.rounding) {
  69. case Tegra::Shader::F2fRoundingOp::None:
  70. return value;
  71. case Tegra::Shader::F2fRoundingOp::Round:
  72. return Operation(OperationCode::FRoundEven, PRECISE, value);
  73. case Tegra::Shader::F2fRoundingOp::Floor:
  74. return Operation(OperationCode::FFloor, PRECISE, value);
  75. case Tegra::Shader::F2fRoundingOp::Ceil:
  76. return Operation(OperationCode::FCeil, PRECISE, value);
  77. case Tegra::Shader::F2fRoundingOp::Trunc:
  78. return Operation(OperationCode::FTrunc, PRECISE, value);
  79. }
  80. UNIMPLEMENTED_MSG("Unimplemented F2F rounding mode {}",
  81. static_cast<u32>(instr.conversion.f2f.rounding.Value()));
  82. return Immediate(0);
  83. }();
  84. value = GetSaturatedFloat(value, instr.alu.saturate_d);
  85. SetInternalFlagsFromFloat(bb, value, instr.generates_cc);
  86. SetRegister(bb, instr.gpr0, value);
  87. break;
  88. }
  89. case OpCode::Id::F2I_R:
  90. case OpCode::Id::F2I_C: {
  91. UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word);
  92. UNIMPLEMENTED_IF_MSG(instr.generates_cc,
  93. "Condition codes generation in F2I is not implemented");
  94. Node value = [&]() {
  95. if (instr.is_b_gpr) {
  96. return GetRegister(instr.gpr20);
  97. } else {
  98. return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.offset);
  99. }
  100. }();
  101. value = GetOperandAbsNegFloat(value, instr.conversion.abs_a, instr.conversion.negate_a);
  102. value = [&]() {
  103. switch (instr.conversion.f2i.rounding) {
  104. case Tegra::Shader::F2iRoundingOp::None:
  105. return value;
  106. case Tegra::Shader::F2iRoundingOp::Floor:
  107. return Operation(OperationCode::FFloor, PRECISE, value);
  108. case Tegra::Shader::F2iRoundingOp::Ceil:
  109. return Operation(OperationCode::FCeil, PRECISE, value);
  110. case Tegra::Shader::F2iRoundingOp::Trunc:
  111. return Operation(OperationCode::FTrunc, PRECISE, value);
  112. default:
  113. UNIMPLEMENTED_MSG("Unimplemented F2I rounding mode {}",
  114. static_cast<u32>(instr.conversion.f2i.rounding.Value()));
  115. return Immediate(0);
  116. }
  117. }();
  118. const bool is_signed = instr.conversion.is_output_signed;
  119. value = SignedOperation(OperationCode::ICastFloat, is_signed, PRECISE, value);
  120. value = ConvertIntegerSize(value, instr.conversion.dest_size, is_signed);
  121. SetRegister(bb, instr.gpr0, value);
  122. break;
  123. }
  124. default:
  125. UNIMPLEMENTED_MSG("Unhandled conversion instruction: {}", opcode->get().GetName());
  126. }
  127. return pc;
  128. }
  129. } // namespace VideoCommon::Shader