summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend/ir
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/frontend/ir')
-rw-r--r--src/shader_recompiler/frontend/ir/basic_block.cpp4
-rw-r--r--src/shader_recompiler/frontend/ir/basic_block.h2
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.cpp200
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.h67
-rw-r--r--src/shader_recompiler/frontend/ir/microinstruction.h12
-rw-r--r--src/shader_recompiler/frontend/ir/modifiers.h28
-rw-r--r--src/shader_recompiler/frontend/ir/opcode.inc139
-rw-r--r--src/shader_recompiler/frontend/ir/pred.h11
8 files changed, 398 insertions, 65 deletions
diff --git a/src/shader_recompiler/frontend/ir/basic_block.cpp b/src/shader_recompiler/frontend/ir/basic_block.cpp
index e795618fc..249251dd0 100644
--- a/src/shader_recompiler/frontend/ir/basic_block.cpp
+++ b/src/shader_recompiler/frontend/ir/basic_block.cpp
@@ -23,8 +23,8 @@ void Block::AppendNewInst(Opcode op, std::initializer_list<Value> args) {
23} 23}
24 24
25Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode op, 25Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode op,
26 std::initializer_list<Value> args) { 26 std::initializer_list<Value> args, u64 flags) {
27 Inst* const inst{std::construct_at(instruction_alloc_pool.allocate(), op)}; 27 Inst* const inst{std::construct_at(instruction_alloc_pool.allocate(), op, flags)};
28 const auto result_it{instructions.insert(insertion_point, *inst)}; 28 const auto result_it{instructions.insert(insertion_point, *inst)};
29 29
30 if (inst->NumArgs() != args.size()) { 30 if (inst->NumArgs() != args.size()) {
diff --git a/src/shader_recompiler/frontend/ir/basic_block.h b/src/shader_recompiler/frontend/ir/basic_block.h
index 4b6b80c4b..ec4a41cb1 100644
--- a/src/shader_recompiler/frontend/ir/basic_block.h
+++ b/src/shader_recompiler/frontend/ir/basic_block.h
@@ -39,7 +39,7 @@ public:
39 39
40 /// Prepends a new instruction to this basic block before the insertion point. 40 /// Prepends a new instruction to this basic block before the insertion point.
41 iterator PrependNewInst(iterator insertion_point, Opcode op, 41 iterator PrependNewInst(iterator insertion_point, Opcode op,
42 std::initializer_list<Value> args = {}); 42 std::initializer_list<Value> args = {}, u64 flags = 0);
43 43
44 /// Adds a new immediate predecessor to the basic block. 44 /// Adds a new immediate predecessor to the basic block.
45 void AddImmediatePredecessor(IR::Block* immediate_predecessor); 45 void AddImmediatePredecessor(IR::Block* immediate_predecessor);
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
index 6450e4b2c..87b253c9a 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
@@ -129,6 +129,58 @@ void IREmitter::SetAttribute(IR::Attribute attribute, const U32& value) {
129 Inst(Opcode::SetAttribute, attribute, value); 129 Inst(Opcode::SetAttribute, attribute, value);
130} 130}
131 131
132U32 IREmitter::WorkgroupIdX() {
133 return Inst<U32>(Opcode::WorkgroupIdX);
134}
135
136U32 IREmitter::WorkgroupIdY() {
137 return Inst<U32>(Opcode::WorkgroupIdY);
138}
139
140U32 IREmitter::WorkgroupIdZ() {
141 return Inst<U32>(Opcode::WorkgroupIdZ);
142}
143
144U32 IREmitter::LocalInvocationIdX() {
145 return Inst<U32>(Opcode::LocalInvocationIdX);
146}
147
148U32 IREmitter::LocalInvocationIdY() {
149 return Inst<U32>(Opcode::LocalInvocationIdY);
150}
151
152U32 IREmitter::LocalInvocationIdZ() {
153 return Inst<U32>(Opcode::LocalInvocationIdZ);
154}
155
156U32 IREmitter::LoadGlobalU8(const U64& address) {
157 return Inst<U32>(Opcode::LoadGlobalU8, address);
158}
159
160U32 IREmitter::LoadGlobalS8(const U64& address) {
161 return Inst<U32>(Opcode::LoadGlobalS8, address);
162}
163
164U32 IREmitter::LoadGlobalU16(const U64& address) {
165 return Inst<U32>(Opcode::LoadGlobalU16, address);
166}
167
168U32 IREmitter::LoadGlobalS16(const U64& address) {
169 return Inst<U32>(Opcode::LoadGlobalS16, address);
170}
171
172U32 IREmitter::LoadGlobal32(const U64& address) {
173 return Inst<U32>(Opcode::LoadGlobal32, address);
174}
175
176Value IREmitter::LoadGlobal64(const U64& address) {
177 return Inst<Value>(Opcode::LoadGlobal64, address);
178}
179
180Value IREmitter::LoadGlobal128(const U64& address) {
181 return Inst<Value>(Opcode::LoadGlobal128, address);
182}
183
132void IREmitter::WriteGlobalU8(const U64& address, const U32& value) { 184void IREmitter::WriteGlobalU8(const U64& address, const U32& value) {
133 Inst(Opcode::WriteGlobalU8, address, value); 185 Inst(Opcode::WriteGlobalU8, address, value);
134} 186}
@@ -173,17 +225,17 @@ U1 IREmitter::GetOverflowFromOp(const Value& op) {
173 return Inst<U1>(Opcode::GetOverflowFromOp, op); 225 return Inst<U1>(Opcode::GetOverflowFromOp, op);
174} 226}
175 227
176U16U32U64 IREmitter::FPAdd(const U16U32U64& a, const U16U32U64& b) { 228U16U32U64 IREmitter::FPAdd(const U16U32U64& a, const U16U32U64& b, FpControl control) {
177 if (a.Type() != a.Type()) { 229 if (a.Type() != a.Type()) {
178 throw InvalidArgument("Mismatching types {} and {}", a.Type(), b.Type()); 230 throw InvalidArgument("Mismatching types {} and {}", a.Type(), b.Type());
179 } 231 }
180 switch (a.Type()) { 232 switch (a.Type()) {
181 case Type::U16: 233 case Type::U16:
182 return Inst<U16>(Opcode::FPAdd16, a, b); 234 return Inst<U16>(Opcode::FPAdd16, Flags{control}, a, b);
183 case Type::U32: 235 case Type::U32:
184 return Inst<U32>(Opcode::FPAdd32, a, b); 236 return Inst<U32>(Opcode::FPAdd32, Flags{control}, a, b);
185 case Type::U64: 237 case Type::U64:
186 return Inst<U64>(Opcode::FPAdd64, a, b); 238 return Inst<U64>(Opcode::FPAdd64, Flags{control}, a, b);
187 default: 239 default:
188 ThrowInvalidType(a.Type()); 240 ThrowInvalidType(a.Type());
189 } 241 }
@@ -191,14 +243,14 @@ U16U32U64 IREmitter::FPAdd(const U16U32U64& a, const U16U32U64& b) {
191 243
192Value IREmitter::CompositeConstruct(const UAny& e1, const UAny& e2) { 244Value IREmitter::CompositeConstruct(const UAny& e1, const UAny& e2) {
193 if (e1.Type() != e2.Type()) { 245 if (e1.Type() != e2.Type()) {
194 throw InvalidArgument("Incompatible types {} {}", e1.Type(), e2.Type()); 246 throw InvalidArgument("Mismatching types {} and {}", e1.Type(), e2.Type());
195 } 247 }
196 return Inst(Opcode::CompositeConstruct2, e1, e2); 248 return Inst(Opcode::CompositeConstruct2, e1, e2);
197} 249}
198 250
199Value IREmitter::CompositeConstruct(const UAny& e1, const UAny& e2, const UAny& e3) { 251Value IREmitter::CompositeConstruct(const UAny& e1, const UAny& e2, const UAny& e3) {
200 if (e1.Type() != e2.Type() || e1.Type() != e3.Type()) { 252 if (e1.Type() != e2.Type() || e1.Type() != e3.Type()) {
201 throw InvalidArgument("Incompatible types {} {} {}", e1.Type(), e2.Type(), e3.Type()); 253 throw InvalidArgument("Mismatching types {}, {}, and {}", e1.Type(), e2.Type(), e3.Type());
202 } 254 }
203 return Inst(Opcode::CompositeConstruct3, e1, e2, e3); 255 return Inst(Opcode::CompositeConstruct3, e1, e2, e3);
204} 256}
@@ -206,8 +258,8 @@ Value IREmitter::CompositeConstruct(const UAny& e1, const UAny& e2, const UAny&
206Value IREmitter::CompositeConstruct(const UAny& e1, const UAny& e2, const UAny& e3, 258Value IREmitter::CompositeConstruct(const UAny& e1, const UAny& e2, const UAny& e3,
207 const UAny& e4) { 259 const UAny& e4) {
208 if (e1.Type() != e2.Type() || e1.Type() != e3.Type() || e1.Type() != e4.Type()) { 260 if (e1.Type() != e2.Type() || e1.Type() != e3.Type() || e1.Type() != e4.Type()) {
209 throw InvalidArgument("Incompatible types {} {} {}", e1.Type(), e2.Type(), e3.Type(), 261 throw InvalidArgument("Mismatching types {}, {}, {}, and {}", e1.Type(), e2.Type(),
210 e4.Type()); 262 e3.Type(), e4.Type());
211 } 263 }
212 return Inst(Opcode::CompositeConstruct4, e1, e2, e3, e4); 264 return Inst(Opcode::CompositeConstruct4, e1, e2, e3, e4);
213} 265}
@@ -219,6 +271,24 @@ UAny IREmitter::CompositeExtract(const Value& vector, size_t element) {
219 return Inst<UAny>(Opcode::CompositeExtract, vector, Imm32(static_cast<u32>(element))); 271 return Inst<UAny>(Opcode::CompositeExtract, vector, Imm32(static_cast<u32>(element)));
220} 272}
221 273
274UAny IREmitter::Select(const U1& condition, const UAny& true_value, const UAny& false_value) {
275 if (true_value.Type() != false_value.Type()) {
276 throw InvalidArgument("Mismatching types {} and {}", true_value.Type(), false_value.Type());
277 }
278 switch (true_value.Type()) {
279 case Type::U8:
280 return Inst<UAny>(Opcode::Select8, condition, true_value, false_value);
281 case Type::U16:
282 return Inst<UAny>(Opcode::Select16, condition, true_value, false_value);
283 case Type::U32:
284 return Inst<UAny>(Opcode::Select32, condition, true_value, false_value);
285 case Type::U64:
286 return Inst<UAny>(Opcode::Select64, condition, true_value, false_value);
287 default:
288 throw InvalidArgument("Invalid type {}", true_value.Type());
289 }
290}
291
222U64 IREmitter::PackUint2x32(const Value& vector) { 292U64 IREmitter::PackUint2x32(const Value& vector) {
223 return Inst<U64>(Opcode::PackUint2x32, vector); 293 return Inst<U64>(Opcode::PackUint2x32, vector);
224} 294}
@@ -243,17 +313,34 @@ Value IREmitter::UnpackDouble2x32(const U64& value) {
243 return Inst<Value>(Opcode::UnpackDouble2x32, value); 313 return Inst<Value>(Opcode::UnpackDouble2x32, value);
244} 314}
245 315
246U16U32U64 IREmitter::FPMul(const U16U32U64& a, const U16U32U64& b) { 316U16U32U64 IREmitter::FPMul(const U16U32U64& a, const U16U32U64& b, FpControl control) {
247 if (a.Type() != b.Type()) { 317 if (a.Type() != b.Type()) {
248 throw InvalidArgument("Mismatching types {} and {}", a.Type(), b.Type()); 318 throw InvalidArgument("Mismatching types {} and {}", a.Type(), b.Type());
249 } 319 }
250 switch (a.Type()) { 320 switch (a.Type()) {
251 case Type::U16: 321 case Type::U16:
252 return Inst<U16>(Opcode::FPMul16, a, b); 322 return Inst<U16>(Opcode::FPMul16, Flags{control}, a, b);
253 case Type::U32: 323 case Type::U32:
254 return Inst<U32>(Opcode::FPMul32, a, b); 324 return Inst<U32>(Opcode::FPMul32, Flags{control}, a, b);
255 case Type::U64: 325 case Type::U64:
256 return Inst<U64>(Opcode::FPMul64, a, b); 326 return Inst<U64>(Opcode::FPMul64, Flags{control}, a, b);
327 default:
328 ThrowInvalidType(a.Type());
329 }
330}
331
332U16U32U64 IREmitter::FPFma(const U16U32U64& a, const U16U32U64& b, const U16U32U64& c,
333 FpControl control) {
334 if (a.Type() != b.Type() || a.Type() != c.Type()) {
335 throw InvalidArgument("Mismatching types {}, {}, and {}", a.Type(), b.Type(), c.Type());
336 }
337 switch (a.Type()) {
338 case Type::U16:
339 return Inst<U16>(Opcode::FPFma16, Flags{control}, a, b, c);
340 case Type::U32:
341 return Inst<U32>(Opcode::FPFma32, Flags{control}, a, b, c);
342 case Type::U64:
343 return Inst<U64>(Opcode::FPFma64, Flags{control}, a, b, c);
257 default: 344 default:
258 ThrowInvalidType(a.Type()); 345 ThrowInvalidType(a.Type());
259 } 346 }
@@ -403,6 +490,91 @@ U16U32U64 IREmitter::FPTrunc(const U16U32U64& value) {
403 } 490 }
404} 491}
405 492
493U32U64 IREmitter::IAdd(const U32U64& a, const U32U64& b) {
494 if (a.Type() != b.Type()) {
495 throw InvalidArgument("Mismatching types {} and {}", a.Type(), b.Type());
496 }
497 switch (a.Type()) {
498 case Type::U32:
499 return Inst<U32>(Opcode::IAdd32, a, b);
500 case Type::U64:
501 return Inst<U64>(Opcode::IAdd64, a, b);
502 default:
503 ThrowInvalidType(a.Type());
504 }
505}
506
507U32 IREmitter::IMul(const U32& a, const U32& b) {
508 return Inst<U32>(Opcode::IMul32, a, b);
509}
510
511U32 IREmitter::INeg(const U32& value) {
512 return Inst<U32>(Opcode::INeg32, value);
513}
514
515U32 IREmitter::IAbs(const U32& value) {
516 return Inst<U32>(Opcode::IAbs32, value);
517}
518
519U32 IREmitter::ShiftLeftLogical(const U32& base, const U32& shift) {
520 return Inst<U32>(Opcode::ShiftLeftLogical32, base, shift);
521}
522
523U32 IREmitter::ShiftRightLogical(const U32& base, const U32& shift) {
524 return Inst<U32>(Opcode::ShiftRightLogical32, base, shift);
525}
526
527U32 IREmitter::ShiftRightArithmetic(const U32& base, const U32& shift) {
528 return Inst<U32>(Opcode::ShiftRightArithmetic32, base, shift);
529}
530
531U32 IREmitter::BitwiseAnd(const U32& a, const U32& b) {
532 return Inst<U32>(Opcode::BitwiseAnd32, a, b);
533}
534
535U32 IREmitter::BitwiseOr(const U32& a, const U32& b) {
536 return Inst<U32>(Opcode::BitwiseOr32, a, b);
537}
538
539U32 IREmitter::BitwiseXor(const U32& a, const U32& b) {
540 return Inst<U32>(Opcode::BitwiseXor32, a, b);
541}
542
543U32 IREmitter::BitFieldInsert(const U32& base, const U32& insert, const U32& offset,
544 const U32& count) {
545 return Inst<U32>(Opcode::BitFieldInsert, base, insert, offset, count);
546}
547
548U32 IREmitter::BitFieldExtract(const U32& base, const U32& offset, const U32& count,
549 bool is_signed) {
550 return Inst<U32>(is_signed ? Opcode::BitFieldSExtract : Opcode::BitFieldUExtract, base, offset,
551 count);
552}
553
554U1 IREmitter::ILessThan(const U32& lhs, const U32& rhs, bool is_signed) {
555 return Inst<U1>(is_signed ? Opcode::SLessThan : Opcode::ULessThan, lhs, rhs);
556}
557
558U1 IREmitter::IEqual(const U32& lhs, const U32& rhs) {
559 return Inst<U1>(Opcode::IEqual, lhs, rhs);
560}
561
562U1 IREmitter::ILessThanEqual(const U32& lhs, const U32& rhs, bool is_signed) {
563 return Inst<U1>(is_signed ? Opcode::SLessThanEqual : Opcode::ULessThanEqual, lhs, rhs);
564}
565
566U1 IREmitter::IGreaterThan(const U32& lhs, const U32& rhs, bool is_signed) {
567 return Inst<U1>(is_signed ? Opcode::SGreaterThan : Opcode::UGreaterThan, lhs, rhs);
568}
569
570U1 IREmitter::INotEqual(const U32& lhs, const U32& rhs) {
571 return Inst<U1>(Opcode::INotEqual, lhs, rhs);
572}
573
574U1 IREmitter::IGreaterThanEqual(const U32& lhs, const U32& rhs, bool is_signed) {
575 return Inst<U1>(is_signed ? Opcode::SGreaterThanEqual : Opcode::UGreaterThanEqual, lhs, rhs);
576}
577
406U1 IREmitter::LogicalOr(const U1& a, const U1& b) { 578U1 IREmitter::LogicalOr(const U1& a, const U1& b) {
407 return Inst<U1>(Opcode::LogicalOr, a, b); 579 return Inst<U1>(Opcode::LogicalOr, a, b);
408} 580}
@@ -411,6 +583,10 @@ U1 IREmitter::LogicalAnd(const U1& a, const U1& b) {
411 return Inst<U1>(Opcode::LogicalAnd, a, b); 583 return Inst<U1>(Opcode::LogicalAnd, a, b);
412} 584}
413 585
586U1 IREmitter::LogicalXor(const U1& a, const U1& b) {
587 return Inst<U1>(Opcode::LogicalXor, a, b);
588}
589
414U1 IREmitter::LogicalNot(const U1& value) { 590U1 IREmitter::LogicalNot(const U1& value) {
415 return Inst<U1>(Opcode::LogicalNot, value); 591 return Inst<U1>(Opcode::LogicalNot, value);
416} 592}
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h
index 1af79f41c..7ff763ecf 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.h
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.h
@@ -4,8 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstring>
8#include <type_traits>
9
7#include "shader_recompiler/frontend/ir/attribute.h" 10#include "shader_recompiler/frontend/ir/attribute.h"
8#include "shader_recompiler/frontend/ir/basic_block.h" 11#include "shader_recompiler/frontend/ir/basic_block.h"
12#include "shader_recompiler/frontend/ir/modifiers.h"
9#include "shader_recompiler/frontend/ir/value.h" 13#include "shader_recompiler/frontend/ir/value.h"
10 14
11namespace Shader::IR { 15namespace Shader::IR {
@@ -52,6 +56,22 @@ public:
52 [[nodiscard]] U32 GetAttribute(IR::Attribute attribute); 56 [[nodiscard]] U32 GetAttribute(IR::Attribute attribute);
53 void SetAttribute(IR::Attribute attribute, const U32& value); 57 void SetAttribute(IR::Attribute attribute, const U32& value);
54 58
59 [[nodiscard]] U32 WorkgroupIdX();
60 [[nodiscard]] U32 WorkgroupIdY();
61 [[nodiscard]] U32 WorkgroupIdZ();
62
63 [[nodiscard]] U32 LocalInvocationIdX();
64 [[nodiscard]] U32 LocalInvocationIdY();
65 [[nodiscard]] U32 LocalInvocationIdZ();
66
67 [[nodiscard]] U32 LoadGlobalU8(const U64& address);
68 [[nodiscard]] U32 LoadGlobalS8(const U64& address);
69 [[nodiscard]] U32 LoadGlobalU16(const U64& address);
70 [[nodiscard]] U32 LoadGlobalS16(const U64& address);
71 [[nodiscard]] U32 LoadGlobal32(const U64& address);
72 [[nodiscard]] Value LoadGlobal64(const U64& address);
73 [[nodiscard]] Value LoadGlobal128(const U64& address);
74
55 void WriteGlobalU8(const U64& address, const U32& value); 75 void WriteGlobalU8(const U64& address, const U32& value);
56 void WriteGlobalS8(const U64& address, const U32& value); 76 void WriteGlobalS8(const U64& address, const U32& value);
57 void WriteGlobalU16(const U64& address, const U32& value); 77 void WriteGlobalU16(const U64& address, const U32& value);
@@ -71,6 +91,8 @@ public:
71 const UAny& e4); 91 const UAny& e4);
72 [[nodiscard]] UAny CompositeExtract(const Value& vector, size_t element); 92 [[nodiscard]] UAny CompositeExtract(const Value& vector, size_t element);
73 93
94 [[nodiscard]] UAny Select(const U1& condition, const UAny& true_value, const UAny& false_value);
95
74 [[nodiscard]] U64 PackUint2x32(const Value& vector); 96 [[nodiscard]] U64 PackUint2x32(const Value& vector);
75 [[nodiscard]] Value UnpackUint2x32(const U64& value); 97 [[nodiscard]] Value UnpackUint2x32(const U64& value);
76 98
@@ -80,8 +102,10 @@ public:
80 [[nodiscard]] U64 PackDouble2x32(const Value& vector); 102 [[nodiscard]] U64 PackDouble2x32(const Value& vector);
81 [[nodiscard]] Value UnpackDouble2x32(const U64& value); 103 [[nodiscard]] Value UnpackDouble2x32(const U64& value);
82 104
83 [[nodiscard]] U16U32U64 FPAdd(const U16U32U64& a, const U16U32U64& b); 105 [[nodiscard]] U16U32U64 FPAdd(const U16U32U64& a, const U16U32U64& b, FpControl control = {});
84 [[nodiscard]] U16U32U64 FPMul(const U16U32U64& a, const U16U32U64& b); 106 [[nodiscard]] U16U32U64 FPMul(const U16U32U64& a, const U16U32U64& b, FpControl control = {});
107 [[nodiscard]] U16U32U64 FPFma(const U16U32U64& a, const U16U32U64& b, const U16U32U64& c,
108 FpControl control = {});
85 109
86 [[nodiscard]] U16U32U64 FPAbs(const U16U32U64& value); 110 [[nodiscard]] U16U32U64 FPAbs(const U16U32U64& value);
87 [[nodiscard]] U16U32U64 FPNeg(const U16U32U64& value); 111 [[nodiscard]] U16U32U64 FPNeg(const U16U32U64& value);
@@ -100,8 +124,31 @@ public:
100 [[nodiscard]] U16U32U64 FPCeil(const U16U32U64& value); 124 [[nodiscard]] U16U32U64 FPCeil(const U16U32U64& value);
101 [[nodiscard]] U16U32U64 FPTrunc(const U16U32U64& value); 125 [[nodiscard]] U16U32U64 FPTrunc(const U16U32U64& value);
102 126
127 [[nodiscard]] U32U64 IAdd(const U32U64& a, const U32U64& b);
128 [[nodiscard]] U32 IMul(const U32& a, const U32& b);
129 [[nodiscard]] U32 INeg(const U32& value);
130 [[nodiscard]] U32 IAbs(const U32& value);
131 [[nodiscard]] U32 ShiftLeftLogical(const U32& base, const U32& shift);
132 [[nodiscard]] U32 ShiftRightLogical(const U32& base, const U32& shift);
133 [[nodiscard]] U32 ShiftRightArithmetic(const U32& base, const U32& shift);
134 [[nodiscard]] U32 BitwiseAnd(const U32& a, const U32& b);
135 [[nodiscard]] U32 BitwiseOr(const U32& a, const U32& b);
136 [[nodiscard]] U32 BitwiseXor(const U32& a, const U32& b);
137 [[nodiscard]] U32 BitFieldInsert(const U32& base, const U32& insert, const U32& offset,
138 const U32& count);
139 [[nodiscard]] U32 BitFieldExtract(const U32& base, const U32& offset, const U32& count,
140 bool is_signed);
141
142 [[nodiscard]] U1 ILessThan(const U32& lhs, const U32& rhs, bool is_signed);
143 [[nodiscard]] U1 IEqual(const U32& lhs, const U32& rhs);
144 [[nodiscard]] U1 ILessThanEqual(const U32& lhs, const U32& rhs, bool is_signed);
145 [[nodiscard]] U1 IGreaterThan(const U32& lhs, const U32& rhs, bool is_signed);
146 [[nodiscard]] U1 INotEqual(const U32& lhs, const U32& rhs);
147 [[nodiscard]] U1 IGreaterThanEqual(const U32& lhs, const U32& rhs, bool is_signed);
148
103 [[nodiscard]] U1 LogicalOr(const U1& a, const U1& b); 149 [[nodiscard]] U1 LogicalOr(const U1& a, const U1& b);
104 [[nodiscard]] U1 LogicalAnd(const U1& a, const U1& b); 150 [[nodiscard]] U1 LogicalAnd(const U1& a, const U1& b);
151 [[nodiscard]] U1 LogicalXor(const U1& a, const U1& b);
105 [[nodiscard]] U1 LogicalNot(const U1& value); 152 [[nodiscard]] U1 LogicalNot(const U1& value);
106 153
107 [[nodiscard]] U32U64 ConvertFToS(size_t bitsize, const U16U32U64& value); 154 [[nodiscard]] U32U64 ConvertFToS(size_t bitsize, const U16U32U64& value);
@@ -118,6 +165,22 @@ private:
118 auto it{block.PrependNewInst(insertion_point, op, {Value{args}...})}; 165 auto it{block.PrependNewInst(insertion_point, op, {Value{args}...})};
119 return T{Value{&*it}}; 166 return T{Value{&*it}};
120 } 167 }
168
169 template <typename T>
170 requires(sizeof(T) <= sizeof(u64) && std::is_trivially_copyable_v<T>) struct Flags {
171 Flags() = default;
172 Flags(T proxy_) : proxy{proxy_} {}
173
174 T proxy;
175 };
176
177 template <typename T = Value, typename FlagType, typename... Args>
178 T Inst(Opcode op, Flags<FlagType> flags, Args... args) {
179 u64 raw_flags{};
180 std::memcpy(&raw_flags, &flags.proxy, sizeof(flags.proxy));
181 auto it{block.PrependNewInst(insertion_point, op, {Value{args}...}, raw_flags)};
182 return T{Value{&*it}};
183 }
121}; 184};
122 185
123} // namespace Shader::IR 186} // namespace Shader::IR
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.h b/src/shader_recompiler/frontend/ir/microinstruction.h
index 7f1ed6710..61849695a 100644
--- a/src/shader_recompiler/frontend/ir/microinstruction.h
+++ b/src/shader_recompiler/frontend/ir/microinstruction.h
@@ -5,7 +5,9 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <cstring>
8#include <span> 9#include <span>
10#include <type_traits>
9#include <vector> 11#include <vector>
10 12
11#include <boost/intrusive/list.hpp> 13#include <boost/intrusive/list.hpp>
@@ -23,7 +25,7 @@ constexpr size_t MAX_ARG_COUNT = 4;
23 25
24class Inst : public boost::intrusive::list_base_hook<> { 26class Inst : public boost::intrusive::list_base_hook<> {
25public: 27public:
26 explicit Inst(Opcode op_) noexcept : op(op_) {} 28 explicit Inst(Opcode op_, u64 flags_) noexcept : op{op_}, flags{flags_} {}
27 29
28 /// Get the number of uses this instruction has. 30 /// Get the number of uses this instruction has.
29 [[nodiscard]] int UseCount() const noexcept { 31 [[nodiscard]] int UseCount() const noexcept {
@@ -73,6 +75,14 @@ public:
73 75
74 void ReplaceUsesWith(Value replacement); 76 void ReplaceUsesWith(Value replacement);
75 77
78 template <typename FlagsType>
79 requires(sizeof(FlagsType) <= sizeof(u64) && std::is_trivially_copyable_v<FlagsType>)
80 [[nodiscard]] FlagsType Flags() const noexcept {
81 FlagsType ret;
82 std::memcpy(&ret, &flags, sizeof(ret));
83 return ret;
84 }
85
76private: 86private:
77 void Use(const Value& value); 87 void Use(const Value& value);
78 void UndoUse(const Value& value); 88 void UndoUse(const Value& value);
diff --git a/src/shader_recompiler/frontend/ir/modifiers.h b/src/shader_recompiler/frontend/ir/modifiers.h
new file mode 100644
index 000000000..28bb9e798
--- /dev/null
+++ b/src/shader_recompiler/frontend/ir/modifiers.h
@@ -0,0 +1,28 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7namespace Shader::IR {
8
9enum class FmzMode {
10 None, // Denorms are not flushed, NAN is propagated (nouveau)
11 FTZ, // Flush denorms to zero, NAN is propagated (D3D11, NVN, GL, VK)
12 FMZ, // Flush denorms to zero, x * 0 == 0 (D3D9)
13};
14
15enum class FpRounding {
16 RN, // Round to nearest even,
17 RM, // Round towards negative infinity
18 RP, // Round towards positive infinity
19 RZ, // Round towards zero
20};
21
22struct FpControl {
23 bool no_contraction{false};
24 FpRounding rounding : 8 = FpRounding::RN;
25 FmzMode fmz_mode : 8 = FmzMode::FTZ;
26};
27static_assert(sizeof(FpControl) <= sizeof(u64));
28} // namespace Shader::IR
diff --git a/src/shader_recompiler/frontend/ir/opcode.inc b/src/shader_recompiler/frontend/ir/opcode.inc
index 40759e96a..4ecb5e936 100644
--- a/src/shader_recompiler/frontend/ir/opcode.inc
+++ b/src/shader_recompiler/frontend/ir/opcode.inc
@@ -35,6 +35,12 @@ OPCODE(SetZFlag, Void, U1,
35OPCODE(SetSFlag, Void, U1, ) 35OPCODE(SetSFlag, Void, U1, )
36OPCODE(SetCFlag, Void, U1, ) 36OPCODE(SetCFlag, Void, U1, )
37OPCODE(SetOFlag, Void, U1, ) 37OPCODE(SetOFlag, Void, U1, )
38OPCODE(WorkgroupIdX, U32, )
39OPCODE(WorkgroupIdY, U32, )
40OPCODE(WorkgroupIdZ, U32, )
41OPCODE(LocalInvocationIdX, U32, )
42OPCODE(LocalInvocationIdY, U32, )
43OPCODE(LocalInvocationIdZ, U32, )
38 44
39// Undefined 45// Undefined
40OPCODE(Undef1, U1, ) 46OPCODE(Undef1, U1, )
@@ -44,6 +50,13 @@ OPCODE(Undef32, U32,
44OPCODE(Undef64, U64, ) 50OPCODE(Undef64, U64, )
45 51
46// Memory operations 52// Memory operations
53OPCODE(LoadGlobalU8, U32, U64, )
54OPCODE(LoadGlobalS8, U32, U64, )
55OPCODE(LoadGlobalU16, U32, U64, )
56OPCODE(LoadGlobalS16, U32, U64, )
57OPCODE(LoadGlobal32, U32, U64, )
58OPCODE(LoadGlobal64, Opaque, U64, )
59OPCODE(LoadGlobal128, Opaque, U64, )
47OPCODE(WriteGlobalU8, Void, U64, U32, ) 60OPCODE(WriteGlobalU8, Void, U64, U32, )
48OPCODE(WriteGlobalS8, Void, U64, U32, ) 61OPCODE(WriteGlobalS8, Void, U64, U32, )
49OPCODE(WriteGlobalU16, Void, U64, U32, ) 62OPCODE(WriteGlobalU16, Void, U64, U32, )
@@ -58,6 +71,12 @@ OPCODE(CompositeConstruct3, Opaque, Opaq
58OPCODE(CompositeConstruct4, Opaque, Opaque, Opaque, Opaque, Opaque, ) 71OPCODE(CompositeConstruct4, Opaque, Opaque, Opaque, Opaque, Opaque, )
59OPCODE(CompositeExtract, Opaque, Opaque, U32, ) 72OPCODE(CompositeExtract, Opaque, Opaque, U32, )
60 73
74// Select operations
75OPCODE(Select8, U8, U1, U8, U8, )
76OPCODE(Select16, U16, U1, U16, U16, )
77OPCODE(Select32, U32, U1, U32, U32, )
78OPCODE(Select64, U64, U1, U64, U64, )
79
61// Bitwise conversions 80// Bitwise conversions
62OPCODE(PackUint2x32, U64, Opaque, ) 81OPCODE(PackUint2x32, U64, Opaque, )
63OPCODE(UnpackUint2x32, Opaque, U64, ) 82OPCODE(UnpackUint2x32, Opaque, U64, )
@@ -74,56 +93,84 @@ OPCODE(GetOverflowFromOp, U1, Opaq
74OPCODE(GetZSCOFromOp, ZSCO, Opaque, ) 93OPCODE(GetZSCOFromOp, ZSCO, Opaque, )
75 94
76// Floating-point operations 95// Floating-point operations
77OPCODE(FPAbs16, U16, U16 ) 96OPCODE(FPAbs16, U16, U16, )
78OPCODE(FPAbs32, U32, U32 ) 97OPCODE(FPAbs32, U32, U32, )
79OPCODE(FPAbs64, U64, U64 ) 98OPCODE(FPAbs64, U64, U64, )
80OPCODE(FPAdd16, U16, U16, U16 ) 99OPCODE(FPAdd16, U16, U16, U16, )
81OPCODE(FPAdd32, U32, U32, U32 ) 100OPCODE(FPAdd32, U32, U32, U32, )
82OPCODE(FPAdd64, U64, U64, U64 ) 101OPCODE(FPAdd64, U64, U64, U64, )
83OPCODE(FPFma16, U16, U16, U16 ) 102OPCODE(FPFma16, U16, U16, U16, U16, )
84OPCODE(FPFma32, U32, U32, U32 ) 103OPCODE(FPFma32, U32, U32, U32, U32, )
85OPCODE(FPFma64, U64, U64, U64 ) 104OPCODE(FPFma64, U64, U64, U64, U64, )
86OPCODE(FPMax32, U32, U32, U32 ) 105OPCODE(FPMax32, U32, U32, U32, )
87OPCODE(FPMax64, U64, U64, U64 ) 106OPCODE(FPMax64, U64, U64, U64, )
88OPCODE(FPMin32, U32, U32, U32 ) 107OPCODE(FPMin32, U32, U32, U32, )
89OPCODE(FPMin64, U64, U64, U64 ) 108OPCODE(FPMin64, U64, U64, U64, )
90OPCODE(FPMul16, U16, U16, U16 ) 109OPCODE(FPMul16, U16, U16, U16, )
91OPCODE(FPMul32, U32, U32, U32 ) 110OPCODE(FPMul32, U32, U32, U32, )
92OPCODE(FPMul64, U64, U64, U64 ) 111OPCODE(FPMul64, U64, U64, U64, )
93OPCODE(FPNeg16, U16, U16 ) 112OPCODE(FPNeg16, U16, U16, )
94OPCODE(FPNeg32, U32, U32 ) 113OPCODE(FPNeg32, U32, U32, )
95OPCODE(FPNeg64, U64, U64 ) 114OPCODE(FPNeg64, U64, U64, )
96OPCODE(FPRecip32, U32, U32 ) 115OPCODE(FPRecip32, U32, U32, )
97OPCODE(FPRecip64, U64, U64 ) 116OPCODE(FPRecip64, U64, U64, )
98OPCODE(FPRecipSqrt32, U32, U32 ) 117OPCODE(FPRecipSqrt32, U32, U32, )
99OPCODE(FPRecipSqrt64, U64, U64 ) 118OPCODE(FPRecipSqrt64, U64, U64, )
100OPCODE(FPSqrt, U32, U32 ) 119OPCODE(FPSqrt, U32, U32, )
101OPCODE(FPSin, U32, U32 ) 120OPCODE(FPSin, U32, U32, )
102OPCODE(FPSinNotReduced, U32, U32 ) 121OPCODE(FPSinNotReduced, U32, U32, )
103OPCODE(FPExp2, U32, U32 ) 122OPCODE(FPExp2, U32, U32, )
104OPCODE(FPExp2NotReduced, U32, U32 ) 123OPCODE(FPExp2NotReduced, U32, U32, )
105OPCODE(FPCos, U32, U32 ) 124OPCODE(FPCos, U32, U32, )
106OPCODE(FPCosNotReduced, U32, U32 ) 125OPCODE(FPCosNotReduced, U32, U32, )
107OPCODE(FPLog2, U32, U32 ) 126OPCODE(FPLog2, U32, U32, )
108OPCODE(FPSaturate16, U16, U16 ) 127OPCODE(FPSaturate16, U16, U16, )
109OPCODE(FPSaturate32, U32, U32 ) 128OPCODE(FPSaturate32, U32, U32, )
110OPCODE(FPSaturate64, U64, U64 ) 129OPCODE(FPSaturate64, U64, U64, )
111OPCODE(FPRoundEven16, U16, U16 ) 130OPCODE(FPRoundEven16, U16, U16, )
112OPCODE(FPRoundEven32, U32, U32 ) 131OPCODE(FPRoundEven32, U32, U32, )
113OPCODE(FPRoundEven64, U64, U64 ) 132OPCODE(FPRoundEven64, U64, U64, )
114OPCODE(FPFloor16, U16, U16 ) 133OPCODE(FPFloor16, U16, U16, )
115OPCODE(FPFloor32, U32, U32 ) 134OPCODE(FPFloor32, U32, U32, )
116OPCODE(FPFloor64, U64, U64 ) 135OPCODE(FPFloor64, U64, U64, )
117OPCODE(FPCeil16, U16, U16 ) 136OPCODE(FPCeil16, U16, U16, )
118OPCODE(FPCeil32, U32, U32 ) 137OPCODE(FPCeil32, U32, U32, )
119OPCODE(FPCeil64, U64, U64 ) 138OPCODE(FPCeil64, U64, U64, )
120OPCODE(FPTrunc16, U16, U16 ) 139OPCODE(FPTrunc16, U16, U16, )
121OPCODE(FPTrunc32, U32, U32 ) 140OPCODE(FPTrunc32, U32, U32, )
122OPCODE(FPTrunc64, U64, U64 ) 141OPCODE(FPTrunc64, U64, U64, )
142
143// Integer operations
144OPCODE(IAdd32, U32, U32, U32, )
145OPCODE(IAdd64, U64, U64, U64, )
146OPCODE(IMul32, U32, U32, U32, )
147OPCODE(INeg32, U32, U32, )
148OPCODE(IAbs32, U32, U32, )
149OPCODE(ShiftLeftLogical32, U32, U32, U32, )
150OPCODE(ShiftRightLogical32, U32, U32, U32, )
151OPCODE(ShiftRightArithmetic32, U32, U32, U32, )
152OPCODE(BitwiseAnd32, U32, U32, U32, )
153OPCODE(BitwiseOr32, U32, U32, U32, )
154OPCODE(BitwiseXor32, U32, U32, U32, )
155OPCODE(BitFieldInsert, U32, U32, U32, U32, U32, )
156OPCODE(BitFieldSExtract, U32, U32, U32, U32, )
157OPCODE(BitFieldUExtract, U32, U32, U32, U32, )
158
159OPCODE(SLessThan, U1, U32, U32, )
160OPCODE(ULessThan, U1, U32, U32, )
161OPCODE(IEqual, U1, U32, U32, )
162OPCODE(SLessThanEqual, U1, U32, U32, )
163OPCODE(ULessThanEqual, U1, U32, U32, )
164OPCODE(SGreaterThan, U1, U32, U32, )
165OPCODE(UGreaterThan, U1, U32, U32, )
166OPCODE(INotEqual, U1, U32, U32, )
167OPCODE(SGreaterThanEqual, U1, U32, U32, )
168OPCODE(UGreaterThanEqual, U1, U32, U32, )
123 169
124// Logical operations 170// Logical operations
125OPCODE(LogicalOr, U1, U1, U1, ) 171OPCODE(LogicalOr, U1, U1, U1, )
126OPCODE(LogicalAnd, U1, U1, U1, ) 172OPCODE(LogicalAnd, U1, U1, U1, )
173OPCODE(LogicalXor, U1, U1, U1, )
127OPCODE(LogicalNot, U1, U1, ) 174OPCODE(LogicalNot, U1, U1, )
128 175
129// Conversion operations 176// Conversion operations
diff --git a/src/shader_recompiler/frontend/ir/pred.h b/src/shader_recompiler/frontend/ir/pred.h
index daf23193f..c6f2f82bf 100644
--- a/src/shader_recompiler/frontend/ir/pred.h
+++ b/src/shader_recompiler/frontend/ir/pred.h
@@ -8,7 +8,16 @@
8 8
9namespace Shader::IR { 9namespace Shader::IR {
10 10
11enum class Pred { P0, P1, P2, P3, P4, P5, P6, PT }; 11enum class Pred : u64 {
12 P0,
13 P1,
14 P2,
15 P3,
16 P4,
17 P5,
18 P6,
19 PT,
20};
12 21
13constexpr size_t NUM_USER_PREDS = 6; 22constexpr size_t NUM_USER_PREDS = 6;
14constexpr size_t NUM_PREDS = 7; 23constexpr size_t NUM_PREDS = 7;