diff options
Diffstat (limited to 'src/shader_recompiler/frontend/ir')
| -rw-r--r-- | src/shader_recompiler/frontend/ir/basic_block.cpp | 4 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/basic_block.h | 2 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/ir_emitter.cpp | 200 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/ir_emitter.h | 67 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/microinstruction.h | 12 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/modifiers.h | 28 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/opcode.inc | 139 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/pred.h | 11 |
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 | ||
| 25 | Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode op, | 25 | Block::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 | ||
| 132 | U32 IREmitter::WorkgroupIdX() { | ||
| 133 | return Inst<U32>(Opcode::WorkgroupIdX); | ||
| 134 | } | ||
| 135 | |||
| 136 | U32 IREmitter::WorkgroupIdY() { | ||
| 137 | return Inst<U32>(Opcode::WorkgroupIdY); | ||
| 138 | } | ||
| 139 | |||
| 140 | U32 IREmitter::WorkgroupIdZ() { | ||
| 141 | return Inst<U32>(Opcode::WorkgroupIdZ); | ||
| 142 | } | ||
| 143 | |||
| 144 | U32 IREmitter::LocalInvocationIdX() { | ||
| 145 | return Inst<U32>(Opcode::LocalInvocationIdX); | ||
| 146 | } | ||
| 147 | |||
| 148 | U32 IREmitter::LocalInvocationIdY() { | ||
| 149 | return Inst<U32>(Opcode::LocalInvocationIdY); | ||
| 150 | } | ||
| 151 | |||
| 152 | U32 IREmitter::LocalInvocationIdZ() { | ||
| 153 | return Inst<U32>(Opcode::LocalInvocationIdZ); | ||
| 154 | } | ||
| 155 | |||
| 156 | U32 IREmitter::LoadGlobalU8(const U64& address) { | ||
| 157 | return Inst<U32>(Opcode::LoadGlobalU8, address); | ||
| 158 | } | ||
| 159 | |||
| 160 | U32 IREmitter::LoadGlobalS8(const U64& address) { | ||
| 161 | return Inst<U32>(Opcode::LoadGlobalS8, address); | ||
| 162 | } | ||
| 163 | |||
| 164 | U32 IREmitter::LoadGlobalU16(const U64& address) { | ||
| 165 | return Inst<U32>(Opcode::LoadGlobalU16, address); | ||
| 166 | } | ||
| 167 | |||
| 168 | U32 IREmitter::LoadGlobalS16(const U64& address) { | ||
| 169 | return Inst<U32>(Opcode::LoadGlobalS16, address); | ||
| 170 | } | ||
| 171 | |||
| 172 | U32 IREmitter::LoadGlobal32(const U64& address) { | ||
| 173 | return Inst<U32>(Opcode::LoadGlobal32, address); | ||
| 174 | } | ||
| 175 | |||
| 176 | Value IREmitter::LoadGlobal64(const U64& address) { | ||
| 177 | return Inst<Value>(Opcode::LoadGlobal64, address); | ||
| 178 | } | ||
| 179 | |||
| 180 | Value IREmitter::LoadGlobal128(const U64& address) { | ||
| 181 | return Inst<Value>(Opcode::LoadGlobal128, address); | ||
| 182 | } | ||
| 183 | |||
| 132 | void IREmitter::WriteGlobalU8(const U64& address, const U32& value) { | 184 | void 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 | ||
| 176 | U16U32U64 IREmitter::FPAdd(const U16U32U64& a, const U16U32U64& b) { | 228 | U16U32U64 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 | ||
| 192 | Value IREmitter::CompositeConstruct(const UAny& e1, const UAny& e2) { | 244 | Value 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 | ||
| 199 | Value IREmitter::CompositeConstruct(const UAny& e1, const UAny& e2, const UAny& e3) { | 251 | Value 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& | |||
| 206 | Value IREmitter::CompositeConstruct(const UAny& e1, const UAny& e2, const UAny& e3, | 258 | Value 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 | ||
| 274 | UAny 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 | |||
| 222 | U64 IREmitter::PackUint2x32(const Value& vector) { | 292 | U64 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 | ||
| 246 | U16U32U64 IREmitter::FPMul(const U16U32U64& a, const U16U32U64& b) { | 316 | U16U32U64 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 | |||
| 332 | U16U32U64 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 | ||
| 493 | U32U64 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 | |||
| 507 | U32 IREmitter::IMul(const U32& a, const U32& b) { | ||
| 508 | return Inst<U32>(Opcode::IMul32, a, b); | ||
| 509 | } | ||
| 510 | |||
| 511 | U32 IREmitter::INeg(const U32& value) { | ||
| 512 | return Inst<U32>(Opcode::INeg32, value); | ||
| 513 | } | ||
| 514 | |||
| 515 | U32 IREmitter::IAbs(const U32& value) { | ||
| 516 | return Inst<U32>(Opcode::IAbs32, value); | ||
| 517 | } | ||
| 518 | |||
| 519 | U32 IREmitter::ShiftLeftLogical(const U32& base, const U32& shift) { | ||
| 520 | return Inst<U32>(Opcode::ShiftLeftLogical32, base, shift); | ||
| 521 | } | ||
| 522 | |||
| 523 | U32 IREmitter::ShiftRightLogical(const U32& base, const U32& shift) { | ||
| 524 | return Inst<U32>(Opcode::ShiftRightLogical32, base, shift); | ||
| 525 | } | ||
| 526 | |||
| 527 | U32 IREmitter::ShiftRightArithmetic(const U32& base, const U32& shift) { | ||
| 528 | return Inst<U32>(Opcode::ShiftRightArithmetic32, base, shift); | ||
| 529 | } | ||
| 530 | |||
| 531 | U32 IREmitter::BitwiseAnd(const U32& a, const U32& b) { | ||
| 532 | return Inst<U32>(Opcode::BitwiseAnd32, a, b); | ||
| 533 | } | ||
| 534 | |||
| 535 | U32 IREmitter::BitwiseOr(const U32& a, const U32& b) { | ||
| 536 | return Inst<U32>(Opcode::BitwiseOr32, a, b); | ||
| 537 | } | ||
| 538 | |||
| 539 | U32 IREmitter::BitwiseXor(const U32& a, const U32& b) { | ||
| 540 | return Inst<U32>(Opcode::BitwiseXor32, a, b); | ||
| 541 | } | ||
| 542 | |||
| 543 | U32 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 | |||
| 548 | U32 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 | |||
| 554 | U1 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 | |||
| 558 | U1 IREmitter::IEqual(const U32& lhs, const U32& rhs) { | ||
| 559 | return Inst<U1>(Opcode::IEqual, lhs, rhs); | ||
| 560 | } | ||
| 561 | |||
| 562 | U1 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 | |||
| 566 | U1 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 | |||
| 570 | U1 IREmitter::INotEqual(const U32& lhs, const U32& rhs) { | ||
| 571 | return Inst<U1>(Opcode::INotEqual, lhs, rhs); | ||
| 572 | } | ||
| 573 | |||
| 574 | U1 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 | |||
| 406 | U1 IREmitter::LogicalOr(const U1& a, const U1& b) { | 578 | U1 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 | ||
| 586 | U1 IREmitter::LogicalXor(const U1& a, const U1& b) { | ||
| 587 | return Inst<U1>(Opcode::LogicalXor, a, b); | ||
| 588 | } | ||
| 589 | |||
| 414 | U1 IREmitter::LogicalNot(const U1& value) { | 590 | U1 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 | ||
| 11 | namespace Shader::IR { | 15 | namespace 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 | ||
| 24 | class Inst : public boost::intrusive::list_base_hook<> { | 26 | class Inst : public boost::intrusive::list_base_hook<> { |
| 25 | public: | 27 | public: |
| 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 | |||
| 76 | private: | 86 | private: |
| 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 | |||
| 7 | namespace Shader::IR { | ||
| 8 | |||
| 9 | enum 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 | |||
| 15 | enum 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 | |||
| 22 | struct FpControl { | ||
| 23 | bool no_contraction{false}; | ||
| 24 | FpRounding rounding : 8 = FpRounding::RN; | ||
| 25 | FmzMode fmz_mode : 8 = FmzMode::FTZ; | ||
| 26 | }; | ||
| 27 | static_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, | |||
| 35 | OPCODE(SetSFlag, Void, U1, ) | 35 | OPCODE(SetSFlag, Void, U1, ) |
| 36 | OPCODE(SetCFlag, Void, U1, ) | 36 | OPCODE(SetCFlag, Void, U1, ) |
| 37 | OPCODE(SetOFlag, Void, U1, ) | 37 | OPCODE(SetOFlag, Void, U1, ) |
| 38 | OPCODE(WorkgroupIdX, U32, ) | ||
| 39 | OPCODE(WorkgroupIdY, U32, ) | ||
| 40 | OPCODE(WorkgroupIdZ, U32, ) | ||
| 41 | OPCODE(LocalInvocationIdX, U32, ) | ||
| 42 | OPCODE(LocalInvocationIdY, U32, ) | ||
| 43 | OPCODE(LocalInvocationIdZ, U32, ) | ||
| 38 | 44 | ||
| 39 | // Undefined | 45 | // Undefined |
| 40 | OPCODE(Undef1, U1, ) | 46 | OPCODE(Undef1, U1, ) |
| @@ -44,6 +50,13 @@ OPCODE(Undef32, U32, | |||
| 44 | OPCODE(Undef64, U64, ) | 50 | OPCODE(Undef64, U64, ) |
| 45 | 51 | ||
| 46 | // Memory operations | 52 | // Memory operations |
| 53 | OPCODE(LoadGlobalU8, U32, U64, ) | ||
| 54 | OPCODE(LoadGlobalS8, U32, U64, ) | ||
| 55 | OPCODE(LoadGlobalU16, U32, U64, ) | ||
| 56 | OPCODE(LoadGlobalS16, U32, U64, ) | ||
| 57 | OPCODE(LoadGlobal32, U32, U64, ) | ||
| 58 | OPCODE(LoadGlobal64, Opaque, U64, ) | ||
| 59 | OPCODE(LoadGlobal128, Opaque, U64, ) | ||
| 47 | OPCODE(WriteGlobalU8, Void, U64, U32, ) | 60 | OPCODE(WriteGlobalU8, Void, U64, U32, ) |
| 48 | OPCODE(WriteGlobalS8, Void, U64, U32, ) | 61 | OPCODE(WriteGlobalS8, Void, U64, U32, ) |
| 49 | OPCODE(WriteGlobalU16, Void, U64, U32, ) | 62 | OPCODE(WriteGlobalU16, Void, U64, U32, ) |
| @@ -58,6 +71,12 @@ OPCODE(CompositeConstruct3, Opaque, Opaq | |||
| 58 | OPCODE(CompositeConstruct4, Opaque, Opaque, Opaque, Opaque, Opaque, ) | 71 | OPCODE(CompositeConstruct4, Opaque, Opaque, Opaque, Opaque, Opaque, ) |
| 59 | OPCODE(CompositeExtract, Opaque, Opaque, U32, ) | 72 | OPCODE(CompositeExtract, Opaque, Opaque, U32, ) |
| 60 | 73 | ||
| 74 | // Select operations | ||
| 75 | OPCODE(Select8, U8, U1, U8, U8, ) | ||
| 76 | OPCODE(Select16, U16, U1, U16, U16, ) | ||
| 77 | OPCODE(Select32, U32, U1, U32, U32, ) | ||
| 78 | OPCODE(Select64, U64, U1, U64, U64, ) | ||
| 79 | |||
| 61 | // Bitwise conversions | 80 | // Bitwise conversions |
| 62 | OPCODE(PackUint2x32, U64, Opaque, ) | 81 | OPCODE(PackUint2x32, U64, Opaque, ) |
| 63 | OPCODE(UnpackUint2x32, Opaque, U64, ) | 82 | OPCODE(UnpackUint2x32, Opaque, U64, ) |
| @@ -74,56 +93,84 @@ OPCODE(GetOverflowFromOp, U1, Opaq | |||
| 74 | OPCODE(GetZSCOFromOp, ZSCO, Opaque, ) | 93 | OPCODE(GetZSCOFromOp, ZSCO, Opaque, ) |
| 75 | 94 | ||
| 76 | // Floating-point operations | 95 | // Floating-point operations |
| 77 | OPCODE(FPAbs16, U16, U16 ) | 96 | OPCODE(FPAbs16, U16, U16, ) |
| 78 | OPCODE(FPAbs32, U32, U32 ) | 97 | OPCODE(FPAbs32, U32, U32, ) |
| 79 | OPCODE(FPAbs64, U64, U64 ) | 98 | OPCODE(FPAbs64, U64, U64, ) |
| 80 | OPCODE(FPAdd16, U16, U16, U16 ) | 99 | OPCODE(FPAdd16, U16, U16, U16, ) |
| 81 | OPCODE(FPAdd32, U32, U32, U32 ) | 100 | OPCODE(FPAdd32, U32, U32, U32, ) |
| 82 | OPCODE(FPAdd64, U64, U64, U64 ) | 101 | OPCODE(FPAdd64, U64, U64, U64, ) |
| 83 | OPCODE(FPFma16, U16, U16, U16 ) | 102 | OPCODE(FPFma16, U16, U16, U16, U16, ) |
| 84 | OPCODE(FPFma32, U32, U32, U32 ) | 103 | OPCODE(FPFma32, U32, U32, U32, U32, ) |
| 85 | OPCODE(FPFma64, U64, U64, U64 ) | 104 | OPCODE(FPFma64, U64, U64, U64, U64, ) |
| 86 | OPCODE(FPMax32, U32, U32, U32 ) | 105 | OPCODE(FPMax32, U32, U32, U32, ) |
| 87 | OPCODE(FPMax64, U64, U64, U64 ) | 106 | OPCODE(FPMax64, U64, U64, U64, ) |
| 88 | OPCODE(FPMin32, U32, U32, U32 ) | 107 | OPCODE(FPMin32, U32, U32, U32, ) |
| 89 | OPCODE(FPMin64, U64, U64, U64 ) | 108 | OPCODE(FPMin64, U64, U64, U64, ) |
| 90 | OPCODE(FPMul16, U16, U16, U16 ) | 109 | OPCODE(FPMul16, U16, U16, U16, ) |
| 91 | OPCODE(FPMul32, U32, U32, U32 ) | 110 | OPCODE(FPMul32, U32, U32, U32, ) |
| 92 | OPCODE(FPMul64, U64, U64, U64 ) | 111 | OPCODE(FPMul64, U64, U64, U64, ) |
| 93 | OPCODE(FPNeg16, U16, U16 ) | 112 | OPCODE(FPNeg16, U16, U16, ) |
| 94 | OPCODE(FPNeg32, U32, U32 ) | 113 | OPCODE(FPNeg32, U32, U32, ) |
| 95 | OPCODE(FPNeg64, U64, U64 ) | 114 | OPCODE(FPNeg64, U64, U64, ) |
| 96 | OPCODE(FPRecip32, U32, U32 ) | 115 | OPCODE(FPRecip32, U32, U32, ) |
| 97 | OPCODE(FPRecip64, U64, U64 ) | 116 | OPCODE(FPRecip64, U64, U64, ) |
| 98 | OPCODE(FPRecipSqrt32, U32, U32 ) | 117 | OPCODE(FPRecipSqrt32, U32, U32, ) |
| 99 | OPCODE(FPRecipSqrt64, U64, U64 ) | 118 | OPCODE(FPRecipSqrt64, U64, U64, ) |
| 100 | OPCODE(FPSqrt, U32, U32 ) | 119 | OPCODE(FPSqrt, U32, U32, ) |
| 101 | OPCODE(FPSin, U32, U32 ) | 120 | OPCODE(FPSin, U32, U32, ) |
| 102 | OPCODE(FPSinNotReduced, U32, U32 ) | 121 | OPCODE(FPSinNotReduced, U32, U32, ) |
| 103 | OPCODE(FPExp2, U32, U32 ) | 122 | OPCODE(FPExp2, U32, U32, ) |
| 104 | OPCODE(FPExp2NotReduced, U32, U32 ) | 123 | OPCODE(FPExp2NotReduced, U32, U32, ) |
| 105 | OPCODE(FPCos, U32, U32 ) | 124 | OPCODE(FPCos, U32, U32, ) |
| 106 | OPCODE(FPCosNotReduced, U32, U32 ) | 125 | OPCODE(FPCosNotReduced, U32, U32, ) |
| 107 | OPCODE(FPLog2, U32, U32 ) | 126 | OPCODE(FPLog2, U32, U32, ) |
| 108 | OPCODE(FPSaturate16, U16, U16 ) | 127 | OPCODE(FPSaturate16, U16, U16, ) |
| 109 | OPCODE(FPSaturate32, U32, U32 ) | 128 | OPCODE(FPSaturate32, U32, U32, ) |
| 110 | OPCODE(FPSaturate64, U64, U64 ) | 129 | OPCODE(FPSaturate64, U64, U64, ) |
| 111 | OPCODE(FPRoundEven16, U16, U16 ) | 130 | OPCODE(FPRoundEven16, U16, U16, ) |
| 112 | OPCODE(FPRoundEven32, U32, U32 ) | 131 | OPCODE(FPRoundEven32, U32, U32, ) |
| 113 | OPCODE(FPRoundEven64, U64, U64 ) | 132 | OPCODE(FPRoundEven64, U64, U64, ) |
| 114 | OPCODE(FPFloor16, U16, U16 ) | 133 | OPCODE(FPFloor16, U16, U16, ) |
| 115 | OPCODE(FPFloor32, U32, U32 ) | 134 | OPCODE(FPFloor32, U32, U32, ) |
| 116 | OPCODE(FPFloor64, U64, U64 ) | 135 | OPCODE(FPFloor64, U64, U64, ) |
| 117 | OPCODE(FPCeil16, U16, U16 ) | 136 | OPCODE(FPCeil16, U16, U16, ) |
| 118 | OPCODE(FPCeil32, U32, U32 ) | 137 | OPCODE(FPCeil32, U32, U32, ) |
| 119 | OPCODE(FPCeil64, U64, U64 ) | 138 | OPCODE(FPCeil64, U64, U64, ) |
| 120 | OPCODE(FPTrunc16, U16, U16 ) | 139 | OPCODE(FPTrunc16, U16, U16, ) |
| 121 | OPCODE(FPTrunc32, U32, U32 ) | 140 | OPCODE(FPTrunc32, U32, U32, ) |
| 122 | OPCODE(FPTrunc64, U64, U64 ) | 141 | OPCODE(FPTrunc64, U64, U64, ) |
| 142 | |||
| 143 | // Integer operations | ||
| 144 | OPCODE(IAdd32, U32, U32, U32, ) | ||
| 145 | OPCODE(IAdd64, U64, U64, U64, ) | ||
| 146 | OPCODE(IMul32, U32, U32, U32, ) | ||
| 147 | OPCODE(INeg32, U32, U32, ) | ||
| 148 | OPCODE(IAbs32, U32, U32, ) | ||
| 149 | OPCODE(ShiftLeftLogical32, U32, U32, U32, ) | ||
| 150 | OPCODE(ShiftRightLogical32, U32, U32, U32, ) | ||
| 151 | OPCODE(ShiftRightArithmetic32, U32, U32, U32, ) | ||
| 152 | OPCODE(BitwiseAnd32, U32, U32, U32, ) | ||
| 153 | OPCODE(BitwiseOr32, U32, U32, U32, ) | ||
| 154 | OPCODE(BitwiseXor32, U32, U32, U32, ) | ||
| 155 | OPCODE(BitFieldInsert, U32, U32, U32, U32, U32, ) | ||
| 156 | OPCODE(BitFieldSExtract, U32, U32, U32, U32, ) | ||
| 157 | OPCODE(BitFieldUExtract, U32, U32, U32, U32, ) | ||
| 158 | |||
| 159 | OPCODE(SLessThan, U1, U32, U32, ) | ||
| 160 | OPCODE(ULessThan, U1, U32, U32, ) | ||
| 161 | OPCODE(IEqual, U1, U32, U32, ) | ||
| 162 | OPCODE(SLessThanEqual, U1, U32, U32, ) | ||
| 163 | OPCODE(ULessThanEqual, U1, U32, U32, ) | ||
| 164 | OPCODE(SGreaterThan, U1, U32, U32, ) | ||
| 165 | OPCODE(UGreaterThan, U1, U32, U32, ) | ||
| 166 | OPCODE(INotEqual, U1, U32, U32, ) | ||
| 167 | OPCODE(SGreaterThanEqual, U1, U32, U32, ) | ||
| 168 | OPCODE(UGreaterThanEqual, U1, U32, U32, ) | ||
| 123 | 169 | ||
| 124 | // Logical operations | 170 | // Logical operations |
| 125 | OPCODE(LogicalOr, U1, U1, U1, ) | 171 | OPCODE(LogicalOr, U1, U1, U1, ) |
| 126 | OPCODE(LogicalAnd, U1, U1, U1, ) | 172 | OPCODE(LogicalAnd, U1, U1, U1, ) |
| 173 | OPCODE(LogicalXor, U1, U1, U1, ) | ||
| 127 | OPCODE(LogicalNot, U1, U1, ) | 174 | OPCODE(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 | ||
| 9 | namespace Shader::IR { | 9 | namespace Shader::IR { |
| 10 | 10 | ||
| 11 | enum class Pred { P0, P1, P2, P3, P4, P5, P6, PT }; | 11 | enum class Pred : u64 { |
| 12 | P0, | ||
| 13 | P1, | ||
| 14 | P2, | ||
| 15 | P3, | ||
| 16 | P4, | ||
| 17 | P5, | ||
| 18 | P6, | ||
| 19 | PT, | ||
| 20 | }; | ||
| 12 | 21 | ||
| 13 | constexpr size_t NUM_USER_PREDS = 6; | 22 | constexpr size_t NUM_USER_PREDS = 6; |
| 14 | constexpr size_t NUM_PREDS = 7; | 23 | constexpr size_t NUM_PREDS = 7; |