shader_ir.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. // Copyright 2018 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <array>
  6. #include <cmath>
  7. #include "common/assert.h"
  8. #include "common/common_types.h"
  9. #include "common/logging/log.h"
  10. #include "video_core/engines/shader_bytecode.h"
  11. #include "video_core/shader/node_helper.h"
  12. #include "video_core/shader/shader_ir.h"
  13. namespace VideoCommon::Shader {
  14. using Tegra::Shader::Attribute;
  15. using Tegra::Shader::Instruction;
  16. using Tegra::Shader::IpaMode;
  17. using Tegra::Shader::Pred;
  18. using Tegra::Shader::PredCondition;
  19. using Tegra::Shader::PredOperation;
  20. using Tegra::Shader::Register;
  21. ShaderIR::ShaderIR(const ProgramCode& program_code, u32 main_offset, CompilerSettings settings,
  22. ConstBufferLocker& locker)
  23. : program_code{program_code}, main_offset{main_offset}, settings{settings}, locker{locker} {
  24. Decode();
  25. PostDecode();
  26. }
  27. ShaderIR::~ShaderIR() = default;
  28. Node ShaderIR::GetRegister(Register reg) {
  29. if (reg != Register::ZeroIndex) {
  30. used_registers.insert(static_cast<u32>(reg));
  31. }
  32. return MakeNode<GprNode>(reg);
  33. }
  34. Node ShaderIR::GetCustomVariable(u32 id) {
  35. return MakeNode<CustomVarNode>(id);
  36. }
  37. Node ShaderIR::GetImmediate19(Instruction instr) {
  38. return Immediate(instr.alu.GetImm20_19());
  39. }
  40. Node ShaderIR::GetImmediate32(Instruction instr) {
  41. return Immediate(instr.alu.GetImm20_32());
  42. }
  43. Node ShaderIR::GetConstBuffer(u64 index_, u64 offset_) {
  44. const auto index = static_cast<u32>(index_);
  45. const auto offset = static_cast<u32>(offset_);
  46. const auto [entry, is_new] = used_cbufs.try_emplace(index);
  47. entry->second.MarkAsUsed(offset);
  48. return MakeNode<CbufNode>(index, Immediate(offset));
  49. }
  50. Node ShaderIR::GetConstBufferIndirect(u64 index_, u64 offset_, Node node) {
  51. const auto index = static_cast<u32>(index_);
  52. const auto offset = static_cast<u32>(offset_);
  53. const auto [entry, is_new] = used_cbufs.try_emplace(index);
  54. entry->second.MarkAsUsedIndirect();
  55. Node final_offset = [&] {
  56. // Attempt to inline constant buffer without a variable offset. This is done to allow
  57. // tracking LDC calls.
  58. if (const auto gpr = std::get_if<GprNode>(&*node)) {
  59. if (gpr->GetIndex() == Register::ZeroIndex) {
  60. return Immediate(offset);
  61. }
  62. }
  63. return Operation(OperationCode::UAdd, NO_PRECISE, std::move(node), Immediate(offset));
  64. }();
  65. return MakeNode<CbufNode>(index, std::move(final_offset));
  66. }
  67. Node ShaderIR::GetPredicate(u64 pred_, bool negated) {
  68. const auto pred = static_cast<Pred>(pred_);
  69. if (pred != Pred::UnusedIndex && pred != Pred::NeverExecute) {
  70. used_predicates.insert(pred);
  71. }
  72. return MakeNode<PredicateNode>(pred, negated);
  73. }
  74. Node ShaderIR::GetPredicate(bool immediate) {
  75. return GetPredicate(static_cast<u64>(immediate ? Pred::UnusedIndex : Pred::NeverExecute));
  76. }
  77. Node ShaderIR::GetInputAttribute(Attribute::Index index, u64 element, Node buffer) {
  78. used_input_attributes.emplace(index);
  79. return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer));
  80. }
  81. Node ShaderIR::GetPhysicalInputAttribute(Tegra::Shader::Register physical_address, Node buffer) {
  82. uses_physical_attributes = true;
  83. return MakeNode<AbufNode>(GetRegister(physical_address), buffer);
  84. }
  85. Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buffer) {
  86. if (index == Attribute::Index::LayerViewportPointSize) {
  87. switch (element) {
  88. case 0:
  89. UNIMPLEMENTED();
  90. break;
  91. case 1:
  92. uses_layer = true;
  93. break;
  94. case 2:
  95. uses_viewport_index = true;
  96. break;
  97. case 3:
  98. uses_point_size = true;
  99. break;
  100. }
  101. }
  102. if (index == Attribute::Index::TessCoordInstanceIDVertexID) {
  103. switch (element) {
  104. case 2:
  105. uses_instance_id = true;
  106. break;
  107. case 3:
  108. uses_vertex_id = true;
  109. break;
  110. default:
  111. break;
  112. }
  113. }
  114. if (index == Attribute::Index::ClipDistances0123 ||
  115. index == Attribute::Index::ClipDistances4567) {
  116. const auto clip_index =
  117. static_cast<u32>((index == Attribute::Index::ClipDistances4567 ? 1 : 0) + element);
  118. used_clip_distances.at(clip_index) = true;
  119. }
  120. used_output_attributes.insert(index);
  121. return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer));
  122. }
  123. Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) const {
  124. const Node node = MakeNode<InternalFlagNode>(flag);
  125. if (negated) {
  126. return Operation(OperationCode::LogicalNegate, node);
  127. }
  128. return node;
  129. }
  130. Node ShaderIR::GetLocalMemory(Node address) {
  131. return MakeNode<LmemNode>(std::move(address));
  132. }
  133. Node ShaderIR::GetSharedMemory(Node address) {
  134. return MakeNode<SmemNode>(std::move(address));
  135. }
  136. Node ShaderIR::GetTemporary(u32 id) {
  137. return GetRegister(Register::ZeroIndex + 1 + id);
  138. }
  139. Node ShaderIR::GetOperandAbsNegFloat(Node value, bool absolute, bool negate) {
  140. if (absolute) {
  141. value = Operation(OperationCode::FAbsolute, NO_PRECISE, std::move(value));
  142. }
  143. if (negate) {
  144. value = Operation(OperationCode::FNegate, NO_PRECISE, std::move(value));
  145. }
  146. return value;
  147. }
  148. Node ShaderIR::GetSaturatedFloat(Node value, bool saturate) {
  149. if (!saturate) {
  150. return value;
  151. }
  152. Node positive_zero = Immediate(std::copysignf(0, 1));
  153. Node positive_one = Immediate(1.0f);
  154. return Operation(OperationCode::FClamp, NO_PRECISE, std::move(value), std::move(positive_zero),
  155. std::move(positive_one));
  156. }
  157. Node ShaderIR::ConvertIntegerSize(Node value, Register::Size size, bool is_signed) {
  158. switch (size) {
  159. case Register::Size::Byte:
  160. value = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed, NO_PRECISE,
  161. std::move(value), Immediate(24));
  162. value = SignedOperation(OperationCode::IArithmeticShiftRight, is_signed, NO_PRECISE,
  163. std::move(value), Immediate(24));
  164. return value;
  165. case Register::Size::Short:
  166. value = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed, NO_PRECISE,
  167. std::move(value), Immediate(16));
  168. value = SignedOperation(OperationCode::IArithmeticShiftRight, is_signed, NO_PRECISE,
  169. std::move(value), Immediate(16));
  170. case Register::Size::Word:
  171. // Default - do nothing
  172. return value;
  173. default:
  174. UNREACHABLE_MSG("Unimplemented conversion size: {}", static_cast<u32>(size));
  175. return value;
  176. }
  177. }
  178. Node ShaderIR::GetOperandAbsNegInteger(Node value, bool absolute, bool negate, bool is_signed) {
  179. if (!is_signed) {
  180. // Absolute or negate on an unsigned is pointless
  181. return value;
  182. }
  183. if (absolute) {
  184. value = Operation(OperationCode::IAbsolute, NO_PRECISE, std::move(value));
  185. }
  186. if (negate) {
  187. value = Operation(OperationCode::INegate, NO_PRECISE, std::move(value));
  188. }
  189. return value;
  190. }
  191. Node ShaderIR::UnpackHalfImmediate(Instruction instr, bool has_negation) {
  192. Node value = Immediate(instr.half_imm.PackImmediates());
  193. if (!has_negation) {
  194. return value;
  195. }
  196. Node first_negate = GetPredicate(instr.half_imm.first_negate != 0);
  197. Node second_negate = GetPredicate(instr.half_imm.second_negate != 0);
  198. return Operation(OperationCode::HNegate, NO_PRECISE, std::move(value), std::move(first_negate),
  199. std::move(second_negate));
  200. }
  201. Node ShaderIR::UnpackHalfFloat(Node value, Tegra::Shader::HalfType type) {
  202. return Operation(OperationCode::HUnpack, type, std::move(value));
  203. }
  204. Node ShaderIR::HalfMerge(Node dest, Node src, Tegra::Shader::HalfMerge merge) {
  205. switch (merge) {
  206. case Tegra::Shader::HalfMerge::H0_H1:
  207. return src;
  208. case Tegra::Shader::HalfMerge::F32:
  209. return Operation(OperationCode::HMergeF32, std::move(src));
  210. case Tegra::Shader::HalfMerge::Mrg_H0:
  211. return Operation(OperationCode::HMergeH0, std::move(dest), std::move(src));
  212. case Tegra::Shader::HalfMerge::Mrg_H1:
  213. return Operation(OperationCode::HMergeH1, std::move(dest), std::move(src));
  214. }
  215. UNREACHABLE();
  216. return src;
  217. }
  218. Node ShaderIR::GetOperandAbsNegHalf(Node value, bool absolute, bool negate) {
  219. if (absolute) {
  220. value = Operation(OperationCode::HAbsolute, NO_PRECISE, std::move(value));
  221. }
  222. if (negate) {
  223. value = Operation(OperationCode::HNegate, NO_PRECISE, std::move(value), GetPredicate(true),
  224. GetPredicate(true));
  225. }
  226. return value;
  227. }
  228. Node ShaderIR::GetSaturatedHalfFloat(Node value, bool saturate) {
  229. if (!saturate) {
  230. return value;
  231. }
  232. Node positive_zero = Immediate(std::copysignf(0, 1));
  233. Node positive_one = Immediate(1.0f);
  234. return Operation(OperationCode::HClamp, NO_PRECISE, std::move(value), std::move(positive_zero),
  235. std::move(positive_one));
  236. }
  237. Node ShaderIR::GetPredicateComparisonFloat(PredCondition condition, Node op_a, Node op_b) {
  238. static constexpr std::array comparison_table{
  239. std::pair{PredCondition::LessThan, OperationCode::LogicalFLessThan},
  240. std::pair{PredCondition::Equal, OperationCode::LogicalFEqual},
  241. std::pair{PredCondition::LessEqual, OperationCode::LogicalFLessEqual},
  242. std::pair{PredCondition::GreaterThan, OperationCode::LogicalFGreaterThan},
  243. std::pair{PredCondition::NotEqual, OperationCode::LogicalFNotEqual},
  244. std::pair{PredCondition::GreaterEqual, OperationCode::LogicalFGreaterEqual},
  245. std::pair{PredCondition::LessThanWithNan, OperationCode::LogicalFLessThan},
  246. std::pair{PredCondition::NotEqualWithNan, OperationCode::LogicalFNotEqual},
  247. std::pair{PredCondition::LessEqualWithNan, OperationCode::LogicalFLessEqual},
  248. std::pair{PredCondition::GreaterThanWithNan, OperationCode::LogicalFGreaterThan},
  249. std::pair{PredCondition::GreaterEqualWithNan, OperationCode::LogicalFGreaterEqual},
  250. };
  251. const auto comparison =
  252. std::find_if(comparison_table.cbegin(), comparison_table.cend(),
  253. [condition](const auto entry) { return condition == entry.first; });
  254. UNIMPLEMENTED_IF_MSG(comparison == comparison_table.cend(),
  255. "Unknown predicate comparison operation");
  256. Node predicate = Operation(comparison->second, NO_PRECISE, op_a, op_b);
  257. if (condition == PredCondition::LessThanWithNan ||
  258. condition == PredCondition::NotEqualWithNan ||
  259. condition == PredCondition::LessEqualWithNan ||
  260. condition == PredCondition::GreaterThanWithNan ||
  261. condition == PredCondition::GreaterEqualWithNan) {
  262. predicate = Operation(OperationCode::LogicalOr, predicate,
  263. Operation(OperationCode::LogicalFIsNan, op_a));
  264. predicate = Operation(OperationCode::LogicalOr, predicate,
  265. Operation(OperationCode::LogicalFIsNan, op_b));
  266. }
  267. return predicate;
  268. }
  269. Node ShaderIR::GetPredicateComparisonInteger(PredCondition condition, bool is_signed, Node op_a,
  270. Node op_b) {
  271. static constexpr std::array comparison_table{
  272. std::pair{PredCondition::LessThan, OperationCode::LogicalILessThan},
  273. std::pair{PredCondition::Equal, OperationCode::LogicalIEqual},
  274. std::pair{PredCondition::LessEqual, OperationCode::LogicalILessEqual},
  275. std::pair{PredCondition::GreaterThan, OperationCode::LogicalIGreaterThan},
  276. std::pair{PredCondition::NotEqual, OperationCode::LogicalINotEqual},
  277. std::pair{PredCondition::GreaterEqual, OperationCode::LogicalIGreaterEqual},
  278. std::pair{PredCondition::LessThanWithNan, OperationCode::LogicalILessThan},
  279. std::pair{PredCondition::NotEqualWithNan, OperationCode::LogicalINotEqual},
  280. std::pair{PredCondition::LessEqualWithNan, OperationCode::LogicalILessEqual},
  281. std::pair{PredCondition::GreaterThanWithNan, OperationCode::LogicalIGreaterThan},
  282. std::pair{PredCondition::GreaterEqualWithNan, OperationCode::LogicalIGreaterEqual},
  283. };
  284. const auto comparison =
  285. std::find_if(comparison_table.cbegin(), comparison_table.cend(),
  286. [condition](const auto entry) { return condition == entry.first; });
  287. UNIMPLEMENTED_IF_MSG(comparison == comparison_table.cend(),
  288. "Unknown predicate comparison operation");
  289. Node predicate = SignedOperation(comparison->second, is_signed, NO_PRECISE, std::move(op_a),
  290. std::move(op_b));
  291. UNIMPLEMENTED_IF_MSG(condition == PredCondition::LessThanWithNan ||
  292. condition == PredCondition::NotEqualWithNan ||
  293. condition == PredCondition::LessEqualWithNan ||
  294. condition == PredCondition::GreaterThanWithNan ||
  295. condition == PredCondition::GreaterEqualWithNan,
  296. "NaN comparisons for integers are not implemented");
  297. return predicate;
  298. }
  299. Node ShaderIR::GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition, Node op_a,
  300. Node op_b) {
  301. static constexpr std::array comparison_table{
  302. std::pair{PredCondition::LessThan, OperationCode::Logical2HLessThan},
  303. std::pair{PredCondition::Equal, OperationCode::Logical2HEqual},
  304. std::pair{PredCondition::LessEqual, OperationCode::Logical2HLessEqual},
  305. std::pair{PredCondition::GreaterThan, OperationCode::Logical2HGreaterThan},
  306. std::pair{PredCondition::NotEqual, OperationCode::Logical2HNotEqual},
  307. std::pair{PredCondition::GreaterEqual, OperationCode::Logical2HGreaterEqual},
  308. std::pair{PredCondition::LessThanWithNan, OperationCode::Logical2HLessThanWithNan},
  309. std::pair{PredCondition::NotEqualWithNan, OperationCode::Logical2HNotEqualWithNan},
  310. std::pair{PredCondition::LessEqualWithNan, OperationCode::Logical2HLessEqualWithNan},
  311. std::pair{PredCondition::GreaterThanWithNan, OperationCode::Logical2HGreaterThanWithNan},
  312. std::pair{PredCondition::GreaterEqualWithNan, OperationCode::Logical2HGreaterEqualWithNan},
  313. };
  314. const auto comparison =
  315. std::find_if(comparison_table.cbegin(), comparison_table.cend(),
  316. [condition](const auto entry) { return condition == entry.first; });
  317. UNIMPLEMENTED_IF_MSG(comparison == comparison_table.cend(),
  318. "Unknown predicate comparison operation");
  319. return Operation(comparison->second, NO_PRECISE, std::move(op_a), std::move(op_b));
  320. }
  321. OperationCode ShaderIR::GetPredicateCombiner(PredOperation operation) {
  322. static constexpr std::array operation_table{
  323. OperationCode::LogicalAnd,
  324. OperationCode::LogicalOr,
  325. OperationCode::LogicalXor,
  326. };
  327. const auto index = static_cast<std::size_t>(operation);
  328. if (index >= operation_table.size()) {
  329. UNIMPLEMENTED_MSG("Unknown predicate operation.");
  330. return {};
  331. }
  332. return operation_table[index];
  333. }
  334. Node ShaderIR::GetConditionCode(Tegra::Shader::ConditionCode cc) const {
  335. switch (cc) {
  336. case Tegra::Shader::ConditionCode::NEU:
  337. return GetInternalFlag(InternalFlag::Zero, true);
  338. default:
  339. UNIMPLEMENTED_MSG("Unimplemented condition code: {}", static_cast<u32>(cc));
  340. return MakeNode<PredicateNode>(Pred::NeverExecute, false);
  341. }
  342. }
  343. void ShaderIR::SetRegister(NodeBlock& bb, Register dest, Node src) {
  344. bb.push_back(Operation(OperationCode::Assign, GetRegister(dest), std::move(src)));
  345. }
  346. void ShaderIR::SetPredicate(NodeBlock& bb, u64 dest, Node src) {
  347. bb.push_back(Operation(OperationCode::LogicalAssign, GetPredicate(dest), std::move(src)));
  348. }
  349. void ShaderIR::SetInternalFlag(NodeBlock& bb, InternalFlag flag, Node value) {
  350. bb.push_back(Operation(OperationCode::LogicalAssign, GetInternalFlag(flag), std::move(value)));
  351. }
  352. void ShaderIR::SetLocalMemory(NodeBlock& bb, Node address, Node value) {
  353. bb.push_back(
  354. Operation(OperationCode::Assign, GetLocalMemory(std::move(address)), std::move(value)));
  355. }
  356. void ShaderIR::SetSharedMemory(NodeBlock& bb, Node address, Node value) {
  357. bb.push_back(
  358. Operation(OperationCode::Assign, GetSharedMemory(std::move(address)), std::move(value)));
  359. }
  360. void ShaderIR::SetTemporary(NodeBlock& bb, u32 id, Node value) {
  361. SetRegister(bb, Register::ZeroIndex + 1 + id, std::move(value));
  362. }
  363. void ShaderIR::SetInternalFlagsFromFloat(NodeBlock& bb, Node value, bool sets_cc) {
  364. if (!sets_cc) {
  365. return;
  366. }
  367. Node zerop = Operation(OperationCode::LogicalFEqual, std::move(value), Immediate(0.0f));
  368. SetInternalFlag(bb, InternalFlag::Zero, std::move(zerop));
  369. LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete");
  370. }
  371. void ShaderIR::SetInternalFlagsFromInteger(NodeBlock& bb, Node value, bool sets_cc) {
  372. if (!sets_cc) {
  373. return;
  374. }
  375. Node zerop = Operation(OperationCode::LogicalIEqual, std::move(value), Immediate(0));
  376. SetInternalFlag(bb, InternalFlag::Zero, std::move(zerop));
  377. LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete");
  378. }
  379. Node ShaderIR::BitfieldExtract(Node value, u32 offset, u32 bits) {
  380. return Operation(OperationCode::UBitfieldExtract, NO_PRECISE, std::move(value),
  381. Immediate(offset), Immediate(bits));
  382. }
  383. Node ShaderIR::BitfieldInsert(Node base, Node insert, u32 offset, u32 bits) {
  384. return Operation(OperationCode::UBitfieldInsert, NO_PRECISE, base, insert, Immediate(offset),
  385. Immediate(bits));
  386. }
  387. std::size_t ShaderIR::DeclareAmend(Node new_amend) {
  388. const std::size_t id = amend_code.size();
  389. amend_code.push_back(new_amend);
  390. return id;
  391. }
  392. u32 ShaderIR::NewCustomVariable() {
  393. return num_custom_variables++;
  394. }
  395. } // namespace VideoCommon::Shader