lower_fp64_to_fp32.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "shader_recompiler/frontend/ir/ir_emitter.h"
  4. #include "shader_recompiler/frontend/ir/opcodes.h"
  5. #include "shader_recompiler/frontend/ir/value.h"
  6. #include "shader_recompiler/ir_opt/passes.h"
  7. namespace Shader::Optimization {
  8. namespace {
  9. constexpr s32 F64ToF32Exp = +1023 - 127;
  10. constexpr s32 F32ToF64Exp = +127 - 1023;
  11. IR::F32 PackedF64ToF32(IR::IREmitter& ir, const IR::Value& packed) {
  12. const IR::U32 lo{ir.CompositeExtract(packed, 0)};
  13. const IR::U32 hi{ir.CompositeExtract(packed, 1)};
  14. const IR::U32 sign{ir.BitFieldExtract(hi, ir.Imm32(31), ir.Imm32(1))};
  15. const IR::U32 exp{ir.BitFieldExtract(hi, ir.Imm32(20), ir.Imm32(11))};
  16. const IR::U32 mantissa_hi{ir.BitFieldExtract(hi, ir.Imm32(0), ir.Imm32(20))};
  17. const IR::U32 mantissa_lo{ir.BitFieldExtract(lo, ir.Imm32(29), ir.Imm32(3))};
  18. const IR::U32 mantissa{
  19. ir.BitwiseOr(ir.ShiftLeftLogical(mantissa_hi, ir.Imm32(3)), mantissa_lo)};
  20. const IR::U32 exp_if_subnorm{
  21. ir.Select(ir.IEqual(exp, ir.Imm32(0)), ir.Imm32(0), ir.IAdd(exp, ir.Imm32(F64ToF32Exp)))};
  22. const IR::U32 exp_if_infnan{
  23. ir.Select(ir.IEqual(exp, ir.Imm32(0x7ff)), ir.Imm32(0xff), exp_if_subnorm)};
  24. const IR::U32 result{
  25. ir.BitwiseOr(ir.ShiftLeftLogical(sign, ir.Imm32(31)),
  26. ir.BitwiseOr(ir.ShiftLeftLogical(exp_if_infnan, ir.Imm32(23)), mantissa))};
  27. return ir.BitCast<IR::F32>(result);
  28. }
  29. IR::Value F32ToPackedF64(IR::IREmitter& ir, const IR::Value& raw) {
  30. const IR::U32 value{ir.BitCast<IR::U32>(IR::F32(raw))};
  31. const IR::U32 sign{ir.BitFieldExtract(value, ir.Imm32(31), ir.Imm32(1))};
  32. const IR::U32 exp{ir.BitFieldExtract(value, ir.Imm32(23), ir.Imm32(8))};
  33. const IR::U32 mantissa{ir.BitFieldExtract(value, ir.Imm32(0), ir.Imm32(23))};
  34. const IR::U32 mantissa_hi{ir.BitFieldExtract(mantissa, ir.Imm32(3), ir.Imm32(20))};
  35. const IR::U32 mantissa_lo{ir.BitFieldExtract(mantissa, ir.Imm32(0), ir.Imm32(3))};
  36. const IR::U32 exp_if_subnorm{
  37. ir.Select(ir.IEqual(exp, ir.Imm32(0)), ir.Imm32(0), ir.IAdd(exp, ir.Imm32(F32ToF64Exp)))};
  38. const IR::U32 exp_if_infnan{
  39. ir.Select(ir.IEqual(exp, ir.Imm32(0xff)), ir.Imm32(0x7ff), exp_if_subnorm)};
  40. const IR::U32 lo{ir.ShiftLeftLogical(mantissa_lo, ir.Imm32(29))};
  41. const IR::U32 hi{
  42. ir.BitwiseOr(ir.ShiftLeftLogical(sign, ir.Imm32(31)),
  43. ir.BitwiseOr(ir.ShiftLeftLogical(exp_if_infnan, ir.Imm32(20)), mantissa_hi))};
  44. return ir.CompositeConstruct(lo, hi);
  45. }
  46. IR::Opcode Replace(IR::Opcode op) {
  47. switch (op) {
  48. case IR::Opcode::FPAbs64:
  49. return IR::Opcode::FPAbs32;
  50. case IR::Opcode::FPAdd64:
  51. return IR::Opcode::FPAdd32;
  52. case IR::Opcode::FPCeil64:
  53. return IR::Opcode::FPCeil32;
  54. case IR::Opcode::FPFloor64:
  55. return IR::Opcode::FPFloor32;
  56. case IR::Opcode::FPFma64:
  57. return IR::Opcode::FPFma32;
  58. case IR::Opcode::FPMul64:
  59. return IR::Opcode::FPMul32;
  60. case IR::Opcode::FPNeg64:
  61. return IR::Opcode::FPNeg32;
  62. case IR::Opcode::FPRoundEven64:
  63. return IR::Opcode::FPRoundEven32;
  64. case IR::Opcode::FPSaturate64:
  65. return IR::Opcode::FPSaturate32;
  66. case IR::Opcode::FPClamp64:
  67. return IR::Opcode::FPClamp32;
  68. case IR::Opcode::FPTrunc64:
  69. return IR::Opcode::FPTrunc32;
  70. case IR::Opcode::CompositeConstructF64x2:
  71. return IR::Opcode::CompositeConstructF32x2;
  72. case IR::Opcode::CompositeConstructF64x3:
  73. return IR::Opcode::CompositeConstructF32x3;
  74. case IR::Opcode::CompositeConstructF64x4:
  75. return IR::Opcode::CompositeConstructF32x4;
  76. case IR::Opcode::CompositeExtractF64x2:
  77. return IR::Opcode::CompositeExtractF32x2;
  78. case IR::Opcode::CompositeExtractF64x3:
  79. return IR::Opcode::CompositeExtractF32x3;
  80. case IR::Opcode::CompositeExtractF64x4:
  81. return IR::Opcode::CompositeExtractF32x4;
  82. case IR::Opcode::CompositeInsertF64x2:
  83. return IR::Opcode::CompositeInsertF32x2;
  84. case IR::Opcode::CompositeInsertF64x3:
  85. return IR::Opcode::CompositeInsertF32x3;
  86. case IR::Opcode::CompositeInsertF64x4:
  87. return IR::Opcode::CompositeInsertF32x4;
  88. case IR::Opcode::FPOrdEqual64:
  89. return IR::Opcode::FPOrdEqual32;
  90. case IR::Opcode::FPUnordEqual64:
  91. return IR::Opcode::FPUnordEqual32;
  92. case IR::Opcode::FPOrdNotEqual64:
  93. return IR::Opcode::FPOrdNotEqual32;
  94. case IR::Opcode::FPUnordNotEqual64:
  95. return IR::Opcode::FPUnordNotEqual32;
  96. case IR::Opcode::FPOrdLessThan64:
  97. return IR::Opcode::FPOrdLessThan32;
  98. case IR::Opcode::FPUnordLessThan64:
  99. return IR::Opcode::FPUnordLessThan32;
  100. case IR::Opcode::FPOrdGreaterThan64:
  101. return IR::Opcode::FPOrdGreaterThan32;
  102. case IR::Opcode::FPUnordGreaterThan64:
  103. return IR::Opcode::FPUnordGreaterThan32;
  104. case IR::Opcode::FPOrdLessThanEqual64:
  105. return IR::Opcode::FPOrdLessThanEqual32;
  106. case IR::Opcode::FPUnordLessThanEqual64:
  107. return IR::Opcode::FPUnordLessThanEqual32;
  108. case IR::Opcode::FPOrdGreaterThanEqual64:
  109. return IR::Opcode::FPOrdGreaterThanEqual32;
  110. case IR::Opcode::FPUnordGreaterThanEqual64:
  111. return IR::Opcode::FPUnordGreaterThanEqual32;
  112. case IR::Opcode::FPIsNan64:
  113. return IR::Opcode::FPIsNan32;
  114. case IR::Opcode::ConvertS16F64:
  115. return IR::Opcode::ConvertS16F32;
  116. case IR::Opcode::ConvertS32F64:
  117. return IR::Opcode::ConvertS32F32;
  118. case IR::Opcode::ConvertS64F64:
  119. return IR::Opcode::ConvertS64F32;
  120. case IR::Opcode::ConvertU16F64:
  121. return IR::Opcode::ConvertU16F32;
  122. case IR::Opcode::ConvertU32F64:
  123. return IR::Opcode::ConvertU32F32;
  124. case IR::Opcode::ConvertU64F64:
  125. return IR::Opcode::ConvertU64F32;
  126. case IR::Opcode::ConvertF32F64:
  127. return IR::Opcode::Identity;
  128. case IR::Opcode::ConvertF64F32:
  129. return IR::Opcode::Identity;
  130. case IR::Opcode::ConvertF64S8:
  131. return IR::Opcode::ConvertF32S8;
  132. case IR::Opcode::ConvertF64S16:
  133. return IR::Opcode::ConvertF32S16;
  134. case IR::Opcode::ConvertF64S32:
  135. return IR::Opcode::ConvertF32S32;
  136. case IR::Opcode::ConvertF64S64:
  137. return IR::Opcode::ConvertF32S64;
  138. case IR::Opcode::ConvertF64U8:
  139. return IR::Opcode::ConvertF32U8;
  140. case IR::Opcode::ConvertF64U16:
  141. return IR::Opcode::ConvertF32U16;
  142. case IR::Opcode::ConvertF64U32:
  143. return IR::Opcode::ConvertF32U32;
  144. case IR::Opcode::ConvertF64U64:
  145. return IR::Opcode::ConvertF32U64;
  146. default:
  147. return op;
  148. }
  149. }
  150. void Lower(IR::Block& block, IR::Inst& inst) {
  151. switch (inst.GetOpcode()) {
  152. case IR::Opcode::PackDouble2x32: {
  153. IR::IREmitter ir(block, IR::Block::InstructionList::s_iterator_to(inst));
  154. inst.ReplaceUsesWith(PackedF64ToF32(ir, inst.Arg(0)));
  155. break;
  156. }
  157. case IR::Opcode::UnpackDouble2x32: {
  158. IR::IREmitter ir(block, IR::Block::InstructionList::s_iterator_to(inst));
  159. inst.ReplaceUsesWith(F32ToPackedF64(ir, inst.Arg(0)));
  160. break;
  161. }
  162. default:
  163. inst.ReplaceOpcode(Replace(inst.GetOpcode()));
  164. break;
  165. }
  166. }
  167. } // Anonymous namespace
  168. void LowerFp64ToFp32(IR::Program& program) {
  169. for (IR::Block* const block : program.blocks) {
  170. for (IR::Inst& inst : block->Instructions()) {
  171. Lower(*block, inst);
  172. }
  173. }
  174. }
  175. } // namespace Shader::Optimization