emit_glsl_integer.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  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. void BitwiseLogicalOp(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b,
  27. char lop) {
  28. const auto result{ctx.var_alloc.Define(inst, GlslVarType::U32)};
  29. ctx.Add("{}={}{}{};", result, a, lop, b);
  30. SetZeroFlag(ctx, inst, result);
  31. SetSignFlag(ctx, inst, result);
  32. }
  33. } // Anonymous namespace
  34. void EmitIAdd32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  35. // Compute the overflow CC first as it requires the original operand values,
  36. // which may be overwritten by the result of the addition
  37. if (IR::Inst * overflow{inst.GetAssociatedPseudoOperation(IR::Opcode::GetOverflowFromOp)}) {
  38. // https://stackoverflow.com/questions/55468823/how-to-detect-integer-overflow-in-c
  39. constexpr u32 s32_max{static_cast<u32>(std::numeric_limits<s32>::max())};
  40. const auto sub_a{fmt::format("{}u-{}", s32_max, a)};
  41. const auto positive_result{fmt::format("int({})>int({})", b, sub_a)};
  42. const auto negative_result{fmt::format("int({})<int({})", b, sub_a)};
  43. ctx.AddU1("{}=int({})>=0?{}:{};", *overflow, a, positive_result, negative_result);
  44. overflow->Invalidate();
  45. }
  46. const auto result{ctx.var_alloc.Define(inst, GlslVarType::U32)};
  47. if (IR::Inst* const carry{inst.GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp)}) {
  48. ctx.uses_cc_carry = true;
  49. ctx.Add("{}=uaddCarry({},{},carry);", result, a, b);
  50. ctx.AddU1("{}=carry!=0;", *carry);
  51. carry->Invalidate();
  52. } else {
  53. ctx.Add("{}={}+{};", result, a, b);
  54. }
  55. SetZeroFlag(ctx, inst, result);
  56. SetSignFlag(ctx, inst, result);
  57. }
  58. void EmitIAdd64(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  59. ctx.AddU64("{}={}+{};", inst, a, b);
  60. }
  61. void EmitISub32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  62. ctx.AddU32("{}={}-{};", inst, a, b);
  63. }
  64. void EmitISub64(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  65. ctx.AddU64("{}={}-{};", inst, a, b);
  66. }
  67. void EmitIMul32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  68. ctx.AddU32("{}=uint({}*{});", inst, a, b);
  69. }
  70. void EmitINeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
  71. ctx.AddU32("{}=uint(-({}));", inst, value);
  72. }
  73. void EmitINeg64(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
  74. ctx.AddU64("{}=-({});", inst, value);
  75. }
  76. void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
  77. ctx.AddU32("{}=abs(int({}));", inst, value);
  78. }
  79. void EmitShiftLeftLogical32(EmitContext& ctx, IR::Inst& inst, std::string_view base,
  80. std::string_view shift) {
  81. ctx.AddU32("{}={}<<{};", inst, base, shift);
  82. }
  83. void EmitShiftLeftLogical64(EmitContext& ctx, IR::Inst& inst, std::string_view base,
  84. std::string_view shift) {
  85. ctx.AddU64("{}={}<<{};", inst, base, shift);
  86. }
  87. void EmitShiftRightLogical32(EmitContext& ctx, IR::Inst& inst, std::string_view base,
  88. std::string_view shift) {
  89. ctx.AddU32("{}={}>>{};", inst, base, shift);
  90. }
  91. void EmitShiftRightLogical64(EmitContext& ctx, IR::Inst& inst, std::string_view base,
  92. std::string_view shift) {
  93. ctx.AddU64("{}={}>>{};", inst, base, shift);
  94. }
  95. void EmitShiftRightArithmetic32(EmitContext& ctx, IR::Inst& inst, std::string_view base,
  96. std::string_view shift) {
  97. ctx.AddU32("{}=int({})>>{};", inst, base, shift);
  98. }
  99. void EmitShiftRightArithmetic64(EmitContext& ctx, IR::Inst& inst, std::string_view base,
  100. std::string_view shift) {
  101. ctx.AddU64("{}=int64_t({})>>{};", inst, base, shift);
  102. }
  103. void EmitBitwiseAnd32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  104. BitwiseLogicalOp(ctx, inst, a, b, '&');
  105. }
  106. void EmitBitwiseOr32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  107. BitwiseLogicalOp(ctx, inst, a, b, '|');
  108. }
  109. void EmitBitwiseXor32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  110. BitwiseLogicalOp(ctx, inst, a, b, '^');
  111. }
  112. void EmitBitFieldInsert(EmitContext& ctx, IR::Inst& inst, std::string_view base,
  113. std::string_view insert, std::string_view offset, std::string_view count) {
  114. ctx.AddU32("{}=bitfieldInsert({},{},int({}),int({}));", inst, base, insert, offset, count);
  115. }
  116. void EmitBitFieldSExtract(EmitContext& ctx, IR::Inst& inst, std::string_view base,
  117. std::string_view offset, std::string_view count) {
  118. const auto result{ctx.var_alloc.Define(inst, GlslVarType::U32)};
  119. ctx.Add("{}=uint(bitfieldExtract(int({}),int({}),int({})));", result, base, offset, count);
  120. SetZeroFlag(ctx, inst, result);
  121. SetSignFlag(ctx, inst, result);
  122. }
  123. void EmitBitFieldUExtract(EmitContext& ctx, IR::Inst& inst, std::string_view base,
  124. std::string_view offset, std::string_view count) {
  125. const auto result{ctx.var_alloc.Define(inst, GlslVarType::U32)};
  126. ctx.Add("{}=uint(bitfieldExtract(uint({}),int({}),int({})));", result, base, offset, count);
  127. SetZeroFlag(ctx, inst, result);
  128. SetSignFlag(ctx, inst, result);
  129. }
  130. void EmitBitReverse32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
  131. ctx.AddU32("{}=bitfieldReverse({});", inst, value);
  132. }
  133. void EmitBitCount32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
  134. ctx.AddU32("{}=bitCount({});", inst, value);
  135. }
  136. void EmitBitwiseNot32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
  137. ctx.AddU32("{}=~{};", inst, value);
  138. }
  139. void EmitFindSMsb32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
  140. ctx.AddU32("{}=findMSB(int({}));", inst, value);
  141. }
  142. void EmitFindUMsb32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
  143. ctx.AddU32("{}=findMSB(uint({}));", inst, value);
  144. }
  145. void EmitSMin32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  146. ctx.AddU32("{}=min(int({}),int({}));", inst, a, b);
  147. }
  148. void EmitUMin32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  149. ctx.AddU32("{}=min(uint({}),uint({}));", inst, a, b);
  150. }
  151. void EmitSMax32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  152. ctx.AddU32("{}=max(int({}),int({}));", inst, a, b);
  153. }
  154. void EmitUMax32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::string_view b) {
  155. ctx.AddU32("{}=max(uint({}),uint({}));", inst, a, b);
  156. }
  157. void EmitSClamp32(EmitContext& ctx, IR::Inst& inst, std::string_view value, std::string_view min,
  158. std::string_view max) {
  159. const auto result{ctx.var_alloc.Define(inst, GlslVarType::U32)};
  160. ctx.Add("{}=clamp(int({}),int({}),int({}));", result, value, min, max);
  161. SetZeroFlag(ctx, inst, result);
  162. SetSignFlag(ctx, inst, result);
  163. }
  164. void EmitUClamp32(EmitContext& ctx, IR::Inst& inst, std::string_view value, std::string_view min,
  165. std::string_view max) {
  166. const auto result{ctx.var_alloc.Define(inst, GlslVarType::U32)};
  167. ctx.Add("{}=clamp(uint({}),uint({}),uint({}));", result, value, min, max);
  168. SetZeroFlag(ctx, inst, result);
  169. SetSignFlag(ctx, inst, result);
  170. }
  171. void EmitSLessThan(EmitContext& ctx, IR::Inst& inst, std::string_view lhs, std::string_view rhs) {
  172. ctx.AddU1("{}=int({})<int({});", inst, lhs, rhs);
  173. }
  174. void EmitULessThan(EmitContext& ctx, IR::Inst& inst, std::string_view lhs, std::string_view rhs) {
  175. ctx.AddU1("{}=uint({})<uint({});", inst, lhs, rhs);
  176. }
  177. void EmitIEqual(EmitContext& ctx, IR::Inst& inst, std::string_view lhs, std::string_view rhs) {
  178. ctx.AddU1("{}={}=={};", inst, lhs, rhs);
  179. }
  180. void EmitSLessThanEqual(EmitContext& ctx, IR::Inst& inst, std::string_view lhs,
  181. std::string_view rhs) {
  182. ctx.AddU1("{}=int({})<=int({});", inst, lhs, rhs);
  183. }
  184. void EmitULessThanEqual(EmitContext& ctx, IR::Inst& inst, std::string_view lhs,
  185. std::string_view rhs) {
  186. ctx.AddU1("{}=uint({})<=uint({});", inst, lhs, rhs);
  187. }
  188. void EmitSGreaterThan(EmitContext& ctx, IR::Inst& inst, std::string_view lhs,
  189. std::string_view rhs) {
  190. ctx.AddU1("{}=int({})>int({});", inst, lhs, rhs);
  191. }
  192. void EmitUGreaterThan(EmitContext& ctx, IR::Inst& inst, std::string_view lhs,
  193. std::string_view rhs) {
  194. ctx.AddU1("{}=uint({})>uint({});", inst, lhs, rhs);
  195. }
  196. void EmitINotEqual(EmitContext& ctx, IR::Inst& inst, std::string_view lhs, std::string_view rhs) {
  197. ctx.AddU1("{}={}!={};", inst, lhs, rhs);
  198. }
  199. void EmitSGreaterThanEqual(EmitContext& ctx, IR::Inst& inst, std::string_view lhs,
  200. std::string_view rhs) {
  201. ctx.AddU1("{}=int({})>=int({});", inst, lhs, rhs);
  202. }
  203. void EmitUGreaterThanEqual(EmitContext& ctx, IR::Inst& inst, std::string_view lhs,
  204. std::string_view rhs) {
  205. ctx.AddU1("{}=uint({})>=uint({});", inst, lhs, rhs);
  206. }
  207. } // namespace Shader::Backend::GLSL