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/ir_emitter.cpp20
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.h5
-rw-r--r--src/shader_recompiler/frontend/ir/microinstruction.cpp26
-rw-r--r--src/shader_recompiler/frontend/ir/microinstruction.h4
-rw-r--r--src/shader_recompiler/frontend/ir/opcode.inc22
-rw-r--r--src/shader_recompiler/frontend/ir/type.cpp2
-rw-r--r--src/shader_recompiler/frontend/ir/type.h1
-rw-r--r--src/shader_recompiler/frontend/ir/value.cpp17
-rw-r--r--src/shader_recompiler/frontend/ir/value.h1
9 files changed, 73 insertions, 25 deletions
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
index 87b253c9a..1c5ae0109 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
@@ -504,6 +504,20 @@ U32U64 IREmitter::IAdd(const U32U64& a, const U32U64& b) {
504 } 504 }
505} 505}
506 506
507U32U64 IREmitter::ISub(const U32U64& a, const U32U64& b) {
508 if (a.Type() != b.Type()) {
509 throw InvalidArgument("Mismatching types {} and {}", a.Type(), b.Type());
510 }
511 switch (a.Type()) {
512 case Type::U32:
513 return Inst<U32>(Opcode::ISub32, a, b);
514 case Type::U64:
515 return Inst<U64>(Opcode::ISub64, a, b);
516 default:
517 ThrowInvalidType(a.Type());
518 }
519}
520
507U32 IREmitter::IMul(const U32& a, const U32& b) { 521U32 IREmitter::IMul(const U32& a, const U32& b) {
508 return Inst<U32>(Opcode::IMul32, a, b); 522 return Inst<U32>(Opcode::IMul32, a, b);
509} 523}
@@ -679,8 +693,8 @@ U32U64 IREmitter::ConvertFToI(size_t bitsize, bool is_signed, const U16U32U64& v
679 } 693 }
680} 694}
681 695
682U32U64 IREmitter::ConvertU(size_t bitsize, const U32U64& value) { 696U32U64 IREmitter::ConvertU(size_t result_bitsize, const U32U64& value) {
683 switch (bitsize) { 697 switch (result_bitsize) {
684 case 32: 698 case 32:
685 switch (value.Type()) { 699 switch (value.Type()) {
686 case Type::U32: 700 case Type::U32:
@@ -703,7 +717,7 @@ U32U64 IREmitter::ConvertU(size_t bitsize, const U32U64& value) {
703 break; 717 break;
704 } 718 }
705 } 719 }
706 throw NotImplementedException("Conversion from {} to {} bits", value.Type(), bitsize); 720 throw NotImplementedException("Conversion from {} to {} bits", value.Type(), result_bitsize);
707} 721}
708 722
709} // namespace Shader::IR 723} // namespace Shader::IR
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h
index 7ff763ecf..84b844898 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.h
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.h
@@ -17,6 +17,8 @@ namespace Shader::IR {
17class IREmitter { 17class IREmitter {
18public: 18public:
19 explicit IREmitter(Block& block_) : block{block_}, insertion_point{block.end()} {} 19 explicit IREmitter(Block& block_) : block{block_}, insertion_point{block.end()} {}
20 explicit IREmitter(Block& block_, Block::iterator insertion_point_)
21 : block{block_}, insertion_point{insertion_point_} {}
20 22
21 Block& block; 23 Block& block;
22 24
@@ -125,6 +127,7 @@ public:
125 [[nodiscard]] U16U32U64 FPTrunc(const U16U32U64& value); 127 [[nodiscard]] U16U32U64 FPTrunc(const U16U32U64& value);
126 128
127 [[nodiscard]] U32U64 IAdd(const U32U64& a, const U32U64& b); 129 [[nodiscard]] U32U64 IAdd(const U32U64& a, const U32U64& b);
130 [[nodiscard]] U32U64 ISub(const U32U64& a, const U32U64& b);
128 [[nodiscard]] U32 IMul(const U32& a, const U32& b); 131 [[nodiscard]] U32 IMul(const U32& a, const U32& b);
129 [[nodiscard]] U32 INeg(const U32& value); 132 [[nodiscard]] U32 INeg(const U32& value);
130 [[nodiscard]] U32 IAbs(const U32& value); 133 [[nodiscard]] U32 IAbs(const U32& value);
@@ -155,7 +158,7 @@ public:
155 [[nodiscard]] U32U64 ConvertFToU(size_t bitsize, const U16U32U64& value); 158 [[nodiscard]] U32U64 ConvertFToU(size_t bitsize, const U16U32U64& value);
156 [[nodiscard]] U32U64 ConvertFToI(size_t bitsize, bool is_signed, const U16U32U64& value); 159 [[nodiscard]] U32U64 ConvertFToI(size_t bitsize, bool is_signed, const U16U32U64& value);
157 160
158 [[nodiscard]] U32U64 ConvertU(size_t bitsize, const U32U64& value); 161 [[nodiscard]] U32U64 ConvertU(size_t result_bitsize, const U32U64& value);
159 162
160private: 163private:
161 IR::Block::iterator insertion_point; 164 IR::Block::iterator insertion_point;
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp
index ecf76e23d..de953838c 100644
--- a/src/shader_recompiler/frontend/ir/microinstruction.cpp
+++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6
5#include "shader_recompiler/exception.h" 7#include "shader_recompiler/exception.h"
6#include "shader_recompiler/frontend/ir/microinstruction.h" 8#include "shader_recompiler/frontend/ir/microinstruction.h"
7#include "shader_recompiler/frontend/ir/type.h" 9#include "shader_recompiler/frontend/ir/type.h"
@@ -44,6 +46,13 @@ bool Inst::MayHaveSideEffects() const noexcept {
44 case Opcode::WriteGlobal32: 46 case Opcode::WriteGlobal32:
45 case Opcode::WriteGlobal64: 47 case Opcode::WriteGlobal64:
46 case Opcode::WriteGlobal128: 48 case Opcode::WriteGlobal128:
49 case Opcode::WriteStorageU8:
50 case Opcode::WriteStorageS8:
51 case Opcode::WriteStorageU16:
52 case Opcode::WriteStorageS16:
53 case Opcode::WriteStorage32:
54 case Opcode::WriteStorage64:
55 case Opcode::WriteStorage128:
47 return true; 56 return true;
48 default: 57 default:
49 return false; 58 return false;
@@ -56,15 +65,19 @@ bool Inst::IsPseudoInstruction() const noexcept {
56 case Opcode::GetSignFromOp: 65 case Opcode::GetSignFromOp:
57 case Opcode::GetCarryFromOp: 66 case Opcode::GetCarryFromOp:
58 case Opcode::GetOverflowFromOp: 67 case Opcode::GetOverflowFromOp:
59 case Opcode::GetZSCOFromOp:
60 return true; 68 return true;
61 default: 69 default:
62 return false; 70 return false;
63 } 71 }
64} 72}
65 73
74bool Inst::AreAllArgsImmediates() const noexcept {
75 return std::all_of(args.begin(), args.begin() + NumArgs(),
76 [](const IR::Value& value) { return value.IsImmediate(); });
77}
78
66bool Inst::HasAssociatedPseudoOperation() const noexcept { 79bool Inst::HasAssociatedPseudoOperation() const noexcept {
67 return zero_inst || sign_inst || carry_inst || overflow_inst || zsco_inst; 80 return zero_inst || sign_inst || carry_inst || overflow_inst;
68} 81}
69 82
70Inst* Inst::GetAssociatedPseudoOperation(IR::Opcode opcode) { 83Inst* Inst::GetAssociatedPseudoOperation(IR::Opcode opcode) {
@@ -82,9 +95,6 @@ Inst* Inst::GetAssociatedPseudoOperation(IR::Opcode opcode) {
82 case Opcode::GetOverflowFromOp: 95 case Opcode::GetOverflowFromOp:
83 CheckPseudoInstruction(overflow_inst, Opcode::GetOverflowFromOp); 96 CheckPseudoInstruction(overflow_inst, Opcode::GetOverflowFromOp);
84 return overflow_inst; 97 return overflow_inst;
85 case Opcode::GetZSCOFromOp:
86 CheckPseudoInstruction(zsco_inst, Opcode::GetZSCOFromOp);
87 return zsco_inst;
88 default: 98 default:
89 throw InvalidArgument("{} is not a pseudo-instruction", opcode); 99 throw InvalidArgument("{} is not a pseudo-instruction", opcode);
90 } 100 }
@@ -176,9 +186,6 @@ void Inst::Use(const Value& value) {
176 case Opcode::GetOverflowFromOp: 186 case Opcode::GetOverflowFromOp:
177 SetPseudoInstruction(value.Inst()->overflow_inst, this); 187 SetPseudoInstruction(value.Inst()->overflow_inst, this);
178 break; 188 break;
179 case Opcode::GetZSCOFromOp:
180 SetPseudoInstruction(value.Inst()->zsco_inst, this);
181 break;
182 default: 189 default:
183 break; 190 break;
184 } 191 }
@@ -200,9 +207,6 @@ void Inst::UndoUse(const Value& value) {
200 case Opcode::GetOverflowFromOp: 207 case Opcode::GetOverflowFromOp:
201 RemovePseudoInstruction(value.Inst()->overflow_inst, Opcode::GetOverflowFromOp); 208 RemovePseudoInstruction(value.Inst()->overflow_inst, Opcode::GetOverflowFromOp);
202 break; 209 break;
203 case Opcode::GetZSCOFromOp:
204 RemovePseudoInstruction(value.Inst()->zsco_inst, Opcode::GetZSCOFromOp);
205 break;
206 default: 210 default:
207 break; 211 break;
208 } 212 }
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.h b/src/shader_recompiler/frontend/ir/microinstruction.h
index 61849695a..22101c9e2 100644
--- a/src/shader_recompiler/frontend/ir/microinstruction.h
+++ b/src/shader_recompiler/frontend/ir/microinstruction.h
@@ -49,6 +49,9 @@ public:
49 /// Pseudo-instructions depend on their parent instructions for their semantics. 49 /// Pseudo-instructions depend on their parent instructions for their semantics.
50 [[nodiscard]] bool IsPseudoInstruction() const noexcept; 50 [[nodiscard]] bool IsPseudoInstruction() const noexcept;
51 51
52 /// Determines if all arguments of this instruction are immediates.
53 [[nodiscard]] bool AreAllArgsImmediates() const noexcept;
54
52 /// Determines if there is a pseudo-operation associated with this instruction. 55 /// Determines if there is a pseudo-operation associated with this instruction.
53 [[nodiscard]] bool HasAssociatedPseudoOperation() const noexcept; 56 [[nodiscard]] bool HasAssociatedPseudoOperation() const noexcept;
54 /// Gets a pseudo-operation associated with this instruction 57 /// Gets a pseudo-operation associated with this instruction
@@ -94,7 +97,6 @@ private:
94 Inst* sign_inst{}; 97 Inst* sign_inst{};
95 Inst* carry_inst{}; 98 Inst* carry_inst{};
96 Inst* overflow_inst{}; 99 Inst* overflow_inst{};
97 Inst* zsco_inst{};
98 std::vector<std::pair<Block*, Value>> phi_operands; 100 std::vector<std::pair<Block*, Value>> phi_operands;
99 u64 flags{}; 101 u64 flags{};
100}; 102};
diff --git a/src/shader_recompiler/frontend/ir/opcode.inc b/src/shader_recompiler/frontend/ir/opcode.inc
index 4ecb5e936..4596bf39f 100644
--- a/src/shader_recompiler/frontend/ir/opcode.inc
+++ b/src/shader_recompiler/frontend/ir/opcode.inc
@@ -24,9 +24,6 @@ OPCODE(GetAttribute, U32, Attr
24OPCODE(SetAttribute, U32, Attribute, ) 24OPCODE(SetAttribute, U32, Attribute, )
25OPCODE(GetAttributeIndexed, U32, U32, ) 25OPCODE(GetAttributeIndexed, U32, U32, )
26OPCODE(SetAttributeIndexed, U32, U32, ) 26OPCODE(SetAttributeIndexed, U32, U32, )
27OPCODE(GetZSCORaw, U32, )
28OPCODE(SetZSCORaw, Void, U32, )
29OPCODE(SetZSCO, Void, ZSCO, )
30OPCODE(GetZFlag, U1, Void, ) 27OPCODE(GetZFlag, U1, Void, )
31OPCODE(GetSFlag, U1, Void, ) 28OPCODE(GetSFlag, U1, Void, )
32OPCODE(GetCFlag, U1, Void, ) 29OPCODE(GetCFlag, U1, Void, )
@@ -65,6 +62,22 @@ OPCODE(WriteGlobal32, Void, U64,
65OPCODE(WriteGlobal64, Void, U64, Opaque, ) 62OPCODE(WriteGlobal64, Void, U64, Opaque, )
66OPCODE(WriteGlobal128, Void, U64, Opaque, ) 63OPCODE(WriteGlobal128, Void, U64, Opaque, )
67 64
65// Storage buffer operations
66OPCODE(LoadStorageU8, U32, U32, U32, )
67OPCODE(LoadStorageS8, U32, U32, U32, )
68OPCODE(LoadStorageU16, U32, U32, U32, )
69OPCODE(LoadStorageS16, U32, U32, U32, )
70OPCODE(LoadStorage32, U32, U32, U32, )
71OPCODE(LoadStorage64, Opaque, U32, U32, )
72OPCODE(LoadStorage128, Opaque, U32, U32, )
73OPCODE(WriteStorageU8, Void, U32, U32, U32, )
74OPCODE(WriteStorageS8, Void, U32, U32, U32, )
75OPCODE(WriteStorageU16, Void, U32, U32, U32, )
76OPCODE(WriteStorageS16, Void, U32, U32, U32, )
77OPCODE(WriteStorage32, Void, U32, U32, U32, )
78OPCODE(WriteStorage64, Void, U32, U32, Opaque, )
79OPCODE(WriteStorage128, Void, U32, U32, Opaque, )
80
68// Vector utility 81// Vector utility
69OPCODE(CompositeConstruct2, Opaque, Opaque, Opaque, ) 82OPCODE(CompositeConstruct2, Opaque, Opaque, Opaque, )
70OPCODE(CompositeConstruct3, Opaque, Opaque, Opaque, Opaque, ) 83OPCODE(CompositeConstruct3, Opaque, Opaque, Opaque, Opaque, )
@@ -90,7 +103,6 @@ OPCODE(GetZeroFromOp, U1, Opaq
90OPCODE(GetSignFromOp, U1, Opaque, ) 103OPCODE(GetSignFromOp, U1, Opaque, )
91OPCODE(GetCarryFromOp, U1, Opaque, ) 104OPCODE(GetCarryFromOp, U1, Opaque, )
92OPCODE(GetOverflowFromOp, U1, Opaque, ) 105OPCODE(GetOverflowFromOp, U1, Opaque, )
93OPCODE(GetZSCOFromOp, ZSCO, Opaque, )
94 106
95// Floating-point operations 107// Floating-point operations
96OPCODE(FPAbs16, U16, U16, ) 108OPCODE(FPAbs16, U16, U16, )
@@ -143,6 +155,8 @@ OPCODE(FPTrunc64, U64, U64,
143// Integer operations 155// Integer operations
144OPCODE(IAdd32, U32, U32, U32, ) 156OPCODE(IAdd32, U32, U32, U32, )
145OPCODE(IAdd64, U64, U64, U64, ) 157OPCODE(IAdd64, U64, U64, U64, )
158OPCODE(ISub32, U32, U32, U32, )
159OPCODE(ISub64, U64, U64, U64, )
146OPCODE(IMul32, U32, U32, U32, ) 160OPCODE(IMul32, U32, U32, U32, )
147OPCODE(INeg32, U32, U32, ) 161OPCODE(INeg32, U32, U32, )
148OPCODE(IAbs32, U32, U32, ) 162OPCODE(IAbs32, U32, U32, )
diff --git a/src/shader_recompiler/frontend/ir/type.cpp b/src/shader_recompiler/frontend/ir/type.cpp
index da1e2a0f6..13cc09195 100644
--- a/src/shader_recompiler/frontend/ir/type.cpp
+++ b/src/shader_recompiler/frontend/ir/type.cpp
@@ -11,7 +11,7 @@ namespace Shader::IR {
11 11
12std::string NameOf(Type type) { 12std::string NameOf(Type type) {
13 static constexpr std::array names{ 13 static constexpr std::array names{
14 "Opaque", "Label", "Reg", "Pred", "Attribute", "U1", "U8", "U16", "U32", "U64", "ZSCO", 14 "Opaque", "Label", "Reg", "Pred", "Attribute", "U1", "U8", "U16", "U32", "U64",
15 }; 15 };
16 const size_t bits{static_cast<size_t>(type)}; 16 const size_t bits{static_cast<size_t>(type)};
17 if (bits == 0) { 17 if (bits == 0) {
diff --git a/src/shader_recompiler/frontend/ir/type.h b/src/shader_recompiler/frontend/ir/type.h
index f753628e8..397875018 100644
--- a/src/shader_recompiler/frontend/ir/type.h
+++ b/src/shader_recompiler/frontend/ir/type.h
@@ -25,7 +25,6 @@ enum class Type {
25 U16 = 1 << 7, 25 U16 = 1 << 7,
26 U32 = 1 << 8, 26 U32 = 1 << 8,
27 U64 = 1 << 9, 27 U64 = 1 << 9,
28 ZSCO = 1 << 10,
29}; 28};
30DECLARE_ENUM_FLAG_OPERATORS(Type) 29DECLARE_ENUM_FLAG_OPERATORS(Type)
31 30
diff --git a/src/shader_recompiler/frontend/ir/value.cpp b/src/shader_recompiler/frontend/ir/value.cpp
index 1e974e88c..59a9b10dc 100644
--- a/src/shader_recompiler/frontend/ir/value.cpp
+++ b/src/shader_recompiler/frontend/ir/value.cpp
@@ -91,26 +91,41 @@ IR::Attribute Value::Attribute() const {
91} 91}
92 92
93bool Value::U1() const { 93bool Value::U1() const {
94 if (IsIdentity()) {
95 return inst->Arg(0).U1();
96 }
94 ValidateAccess(Type::U1); 97 ValidateAccess(Type::U1);
95 return imm_u1; 98 return imm_u1;
96} 99}
97 100
98u8 Value::U8() const { 101u8 Value::U8() const {
102 if (IsIdentity()) {
103 return inst->Arg(0).U8();
104 }
99 ValidateAccess(Type::U8); 105 ValidateAccess(Type::U8);
100 return imm_u8; 106 return imm_u8;
101} 107}
102 108
103u16 Value::U16() const { 109u16 Value::U16() const {
110 if (IsIdentity()) {
111 return inst->Arg(0).U16();
112 }
104 ValidateAccess(Type::U16); 113 ValidateAccess(Type::U16);
105 return imm_u16; 114 return imm_u16;
106} 115}
107 116
108u32 Value::U32() const { 117u32 Value::U32() const {
118 if (IsIdentity()) {
119 return inst->Arg(0).U32();
120 }
109 ValidateAccess(Type::U32); 121 ValidateAccess(Type::U32);
110 return imm_u32; 122 return imm_u32;
111} 123}
112 124
113u64 Value::U64() const { 125u64 Value::U64() const {
126 if (IsIdentity()) {
127 return inst->Arg(0).U64();
128 }
114 ValidateAccess(Type::U64); 129 ValidateAccess(Type::U64);
115 return imm_u64; 130 return imm_u64;
116} 131}
@@ -142,8 +157,6 @@ bool Value::operator==(const Value& other) const {
142 return imm_u32 == other.imm_u32; 157 return imm_u32 == other.imm_u32;
143 case Type::U64: 158 case Type::U64:
144 return imm_u64 == other.imm_u64; 159 return imm_u64 == other.imm_u64;
145 case Type::ZSCO:
146 throw NotImplementedException("ZSCO comparison");
147 } 160 }
148 throw LogicError("Invalid type {}", type); 161 throw LogicError("Invalid type {}", type);
149} 162}
diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h
index 368119921..31f831794 100644
--- a/src/shader_recompiler/frontend/ir/value.h
+++ b/src/shader_recompiler/frontend/ir/value.h
@@ -96,6 +96,5 @@ using U64 = TypedValue<Type::U64>;
96using U32U64 = TypedValue<Type::U32 | Type::U64>; 96using U32U64 = TypedValue<Type::U32 | Type::U64>;
97using U16U32U64 = TypedValue<Type::U16 | Type::U32 | Type::U64>; 97using U16U32U64 = TypedValue<Type::U16 | Type::U32 | Type::U64>;
98using UAny = TypedValue<Type::U8 | Type::U16 | Type::U32 | Type::U64>; 98using UAny = TypedValue<Type::U8 | Type::U16 | Type::U32 | Type::U64>;
99using ZSCO = TypedValue<Type::ZSCO>;
100 99
101} // namespace Shader::IR 100} // namespace Shader::IR