integer_shift_left.cpp 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/bit_field.h"
  5. #include "common/common_types.h"
  6. #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
  7. namespace Shader::Maxwell {
  8. namespace {
  9. void SHL(TranslatorVisitor& v, u64 insn, const IR::U32& unsafe_shift) {
  10. union {
  11. u64 insn;
  12. BitField<0, 8, IR::Reg> dest_reg;
  13. BitField<8, 8, IR::Reg> src_reg_a;
  14. BitField<39, 1, u64> w;
  15. BitField<43, 1, u64> x;
  16. BitField<47, 1, u64> cc;
  17. } const shl{insn};
  18. if (shl.x != 0) {
  19. throw NotImplementedException("SHL.X");
  20. }
  21. if (shl.cc != 0) {
  22. throw NotImplementedException("SHL.CC");
  23. }
  24. const IR::U32 base{v.X(shl.src_reg_a)};
  25. IR::U32 result;
  26. if (shl.w != 0) {
  27. // When .W is set, the shift value is wrapped
  28. // To emulate this we just have to wrap it ourselves.
  29. const IR::U32 shift{v.ir.BitwiseAnd(unsafe_shift, v.ir.Imm32(31))};
  30. result = v.ir.ShiftLeftLogical(base, shift);
  31. } else {
  32. // When .W is not set, the shift value is clamped between 0 and 32.
  33. // To emulate this we have to have in mind the special shift of 32, that evaluates as 0.
  34. // We can safely evaluate an out of bounds shift according to the SPIR-V specification:
  35. //
  36. // https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpShiftLeftLogical
  37. // "Shift is treated as unsigned. The resulting value is undefined if Shift is greater than
  38. // or equal to the bit width of the components of Base."
  39. //
  40. // And on the GLASM specification it is also safe to evaluate out of bounds:
  41. //
  42. // https://www.khronos.org/registry/OpenGL/extensions/NV/NV_gpu_program4.txt
  43. // "The results of a shift operation ("<<") are undefined if the value of the second operand
  44. // is negative, or greater than or equal to the number of bits in the first operand."
  45. //
  46. // Emphasis on undefined results in contrast to undefined behavior.
  47. //
  48. const IR::U1 is_safe{v.ir.ILessThan(unsafe_shift, v.ir.Imm32(32), false)};
  49. const IR::U32 unsafe_result{v.ir.ShiftLeftLogical(base, unsafe_shift)};
  50. result = IR::U32{v.ir.Select(is_safe, unsafe_result, v.ir.Imm32(0))};
  51. }
  52. v.X(shl.dest_reg, result);
  53. }
  54. } // Anonymous namespace
  55. void TranslatorVisitor::SHL_reg(u64 insn) {
  56. SHL(*this, insn, GetReg20(insn));
  57. }
  58. void TranslatorVisitor::SHL_cbuf(u64 insn) {
  59. SHL(*this, insn, GetCbuf(insn));
  60. }
  61. void TranslatorVisitor::SHL_imm(u64 insn) {
  62. SHL(*this, insn, GetImm20(insn));
  63. }
  64. } // namespace Shader::Maxwell