emit_glsl_integer.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <string_view>
  5. #include "shader_recompiler/backend/glsl/emit_context.h"
  6. #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
  7. #include "shader_recompiler/frontend/ir/value.h"
  8. namespace Shader::Backend::GLSL {
  9. namespace {
  10. void SetZeroFlag(EmitContext& ctx, IR::Inst& inst, std::string_view result) {
  11. IR::Inst* const zero{inst.GetAssociatedPseudoOperation(IR::Opcode::GetZeroFromOp)};
  12. if (!zero) {
  13. return;
  14. }
  15. ctx.AddU1("{}={}==0;", *zero, result);
  16. zero->Invalidate();
  17. }
  18. void SetSignFlag(EmitContext& ctx, IR::Inst& inst, std::string_view result) {
  19. IR::Inst* const sign{inst.GetAssociatedPseudoOperation(IR::Opcode::GetSignFromOp)};
  20. if (!sign) {
  21. return;
  22. }
  23. ctx.AddU1("{}=int({})<0;", *sign, result);
  24. sign->Invalidate();
  25. }
  26. } // Anonymous namespace
  27. void EmitIAdd32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  28. const auto result{ctx.var_alloc.Define(inst, GlslVarType::U32)};
  29. if (IR::Inst* const carry{inst.GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp)}) {
  30. ctx.uses_cc_carry = true;
  31. ctx.Add("iadd_op_b={};{}=uaddCarry({},{},carry);", b, result, a, b);
  32. ctx.AddU1("{}=carry!=0;", *carry);
  33. carry->Invalidate();
  34. } else {
  35. ctx.Add("{}={}+{};", result, a, b);
  36. }
  37. SetZeroFlag(ctx, inst, result);
  38. SetSignFlag(ctx, inst, result);
  39. if (IR::Inst * overflow{inst.GetAssociatedPseudoOperation(IR::Opcode::GetOverflowFromOp)}) {
  40. // https://stackoverflow.com/questions/55468823/how-to-detect-integer-overflow-in-c
  41. constexpr u32 s32_max{static_cast<u32>(std::numeric_limits<s32>::max())};
  42. const auto sub_a{fmt::format("{}u-{}", s32_max, a)};
  43. const auto op_b{ctx.uses_cc_carry ? "iadd_op_b" : b};
  44. ctx.AddU1("{}=int({})>=0?int({})>int({}):int({})<int({});", *overflow, a, op_b, sub_a, op_b,
  45. sub_a);
  46. overflow->Invalidate();
  47. }
  48. }
  49. void EmitIAdd64(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  50. ctx.AddU64("{}={}+{};", inst, a, b);
  51. }
  52. void EmitISub32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  53. ctx.AddU32("{}={}-{};", inst, a, b);
  54. }
  55. void EmitISub64(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  56. ctx.AddU64("{}={}-{};", inst, a, b);
  57. }
  58. void EmitIMul32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  59. ctx.AddU32("{}=uint({}*{});", inst, a, b);
  60. }
  61. void EmitINeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
  62. ctx.AddU32("{}=uint(-({}));", inst, value);
  63. }
  64. void EmitINeg64(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
  65. ctx.AddU64("{}=-({});", inst, value);
  66. }
  67. void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
  68. ctx.AddU32("{}=abs(int({}));", inst, value);
  69. }
  70. void EmitIAbs64(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
  71. ctx.AddU64("{}=abs(int64_t({}));", inst, value);
  72. }
  73. void EmitShiftLeftLogical32(EmitContext& ctx, IR::Inst& inst, std::string_view base,
  74. std::string_view shift) {
  75. ctx.AddU32("{}={}<<{};", inst, base, shift);
  76. }
  77. void EmitShiftLeftLogical64(EmitContext& ctx, IR::Inst& inst, std::string_view base,
  78. std::string_view shift) {
  79. ctx.AddU64("{}={}<<{};", inst, base, shift);
  80. }
  81. void EmitShiftRightLogical32(EmitContext& ctx, IR::Inst& inst, std::string_view base,
  82. std::string_view shift) {
  83. ctx.AddU32("{}={}>>{};", inst, base, shift);
  84. }
  85. void EmitShiftRightLogical64(EmitContext& ctx, IR::Inst& inst, std::string_view base,
  86. std::string_view shift) {
  87. ctx.AddU64("{}={}>>{};", inst, base, shift);
  88. }
  89. void EmitShiftRightArithmetic32(EmitContext& ctx, IR::Inst& inst, std::string_view base,
  90. std::string_view shift) {
  91. ctx.AddU32("{}=int({})>>{};", inst, base, shift);
  92. }
  93. void EmitShiftRightArithmetic64(EmitContext& ctx, IR::Inst& inst, std::string_view base,
  94. std::string_view shift) {
  95. ctx.AddU64("{}=int64_t({})>>{};", inst, base, shift);
  96. }
  97. void EmitBitwiseAnd32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  98. ctx.AddU32("{}={}&{};", inst, a, b);
  99. }
  100. void EmitBitwiseOr32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  101. ctx.AddU32("{}={}|{};", inst, a, b);
  102. }
  103. void EmitBitwiseXor32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  104. ctx.AddU32("{}={}^{};", inst, a, b);
  105. }
  106. void EmitBitFieldInsert(EmitContext& ctx, IR::Inst& inst, std::string_view base,
  107. std::string_view insert, std::string_view offset, std::string_view count) {
  108. ctx.AddU32("{}=bitfieldInsert({},{},int({}),int({}));", inst, base, insert, offset, count);
  109. }
  110. void EmitBitFieldSExtract(EmitContext& ctx, IR::Inst& inst, std::string_view base,
  111. std::string_view offset, std::string_view count) {
  112. const auto result{ctx.var_alloc.Define(inst, GlslVarType::U32)};
  113. ctx.Add("{}=uint(bitfieldExtract(int({}),int({}),int({})));", result, base, offset, count);
  114. SetZeroFlag(ctx, inst, result);
  115. SetSignFlag(ctx, inst, result);
  116. }
  117. void EmitBitFieldUExtract(EmitContext& ctx, IR::Inst& inst, std::string_view base,
  118. std::string_view offset, std::string_view count) {
  119. const auto result{ctx.var_alloc.Define(inst, GlslVarType::U32)};
  120. ctx.Add("{}=uint(bitfieldExtract(uint({}),int({}),int({})));", result, base, offset, count);
  121. SetZeroFlag(ctx, inst, result);
  122. SetSignFlag(ctx, inst, result);
  123. }
  124. void EmitBitReverse32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
  125. ctx.AddU32("{}=bitfieldReverse({});", inst, value);
  126. }
  127. void EmitBitCount32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
  128. ctx.AddU32("{}=bitCount({});", inst, value);
  129. }
  130. void EmitBitwiseNot32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
  131. ctx.AddU32("{}=~{};", inst, value);
  132. }
  133. void EmitFindSMsb32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
  134. ctx.AddU32("{}=findMSB(int({}));", inst, value);
  135. }
  136. void EmitFindUMsb32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
  137. ctx.AddU32("{}=findMSB(uint({}));", inst, value);
  138. }
  139. void EmitSMin32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  140. ctx.AddU32("{}=min(int({}),int({}));", inst, a, b);
  141. }
  142. void EmitUMin32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  143. ctx.AddU32("{}=min(uint({}),uint({}));", inst, a, b);
  144. }
  145. void EmitSMax32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  146. ctx.AddU32("{}=max(int({}),int({}));", inst, a, b);
  147. }
  148. void EmitUMax32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  149. ctx.AddU32("{}=max(uint({}),uint({}));", inst, a, b);
  150. }
  151. void EmitSClamp32(EmitContext& ctx, IR::Inst& inst, std::string_view value, std::string_view min,
  152. std::string_view max) {
  153. const auto result{ctx.var_alloc.Define(inst, GlslVarType::U32)};
  154. ctx.Add("{}=clamp(int({}),int({}),int({}));", result, value, min, max);
  155. SetZeroFlag(ctx, inst, result);
  156. SetSignFlag(ctx, inst, result);
  157. }
  158. void EmitUClamp32(EmitContext& ctx, IR::Inst& inst, std::string_view value, std::string_view min,
  159. std::string_view max) {
  160. const auto result{ctx.var_alloc.Define(inst, GlslVarType::U32)};
  161. ctx.Add("{}=clamp(uint({}),uint({}),uint({}));", result, value, min, max);
  162. SetZeroFlag(ctx, inst, result);
  163. SetSignFlag(ctx, inst, result);
  164. }
  165. void EmitSLessThan(EmitContext& ctx, IR::Inst& inst, std::string_view lhs, std::string_view rhs) {
  166. ctx.AddU1("{}=int({})<int({});", inst, lhs, rhs);
  167. }
  168. void EmitULessThan(EmitContext& ctx, IR::Inst& inst, std::string_view lhs, std::string_view rhs) {
  169. ctx.AddU1("{}=uint({})<uint({});", inst, lhs, rhs);
  170. }
  171. void EmitIEqual(EmitContext& ctx, IR::Inst& inst, std::string_view lhs, std::string_view rhs) {
  172. ctx.AddU1("{}={}=={};", inst, lhs, rhs);
  173. }
  174. void EmitSLessThanEqual(EmitContext& ctx, IR::Inst& inst, std::string_view lhs,
  175. std::string_view rhs) {
  176. ctx.AddU1("{}=int({})<=int({});", inst, lhs, rhs);
  177. }
  178. void EmitULessThanEqual(EmitContext& ctx, IR::Inst& inst, std::string_view lhs,
  179. std::string_view rhs) {
  180. ctx.AddU1("{}=uint({})<=uint({});", inst, lhs, rhs);
  181. }
  182. void EmitSGreaterThan(EmitContext& ctx, IR::Inst& inst, std::string_view lhs,
  183. std::string_view rhs) {
  184. ctx.AddU1("{}=int({})>int({});", inst, lhs, rhs);
  185. }
  186. void EmitUGreaterThan(EmitContext& ctx, IR::Inst& inst, std::string_view lhs,
  187. std::string_view rhs) {
  188. ctx.AddU1("{}=uint({})>uint({});", inst, lhs, rhs);
  189. }
  190. void EmitINotEqual(EmitContext& ctx, IR::Inst& inst, std::string_view lhs, std::string_view rhs) {
  191. ctx.AddU1("{}={}!={};", inst, lhs, rhs);
  192. }
  193. void EmitSGreaterThanEqual(EmitContext& ctx, IR::Inst& inst, std::string_view lhs,
  194. std::string_view rhs) {
  195. ctx.AddU1("{}=int({})>=int({});", inst, lhs, rhs);
  196. }
  197. void EmitUGreaterThanEqual(EmitContext& ctx, IR::Inst& inst, std::string_view lhs,
  198. std::string_view rhs) {
  199. ctx.AddU1("{}=uint({})>=uint({});", inst, lhs, rhs);
  200. }
  201. } // namespace Shader::Backend::GLSL