summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2019-11-07 01:30:01 -0500
committerGravatar GitHub2019-11-07 01:30:01 -0500
commitb6ae48966d2e914d6c51f62e9eb818fb7aec7c1d (patch)
tree3798491ae7e3fa7d3d88f7bc97ffe4d90397515e
parentbuffer_cache: Add missing includes (#3079) (diff)
parentshader/control_flow: Specify constness on caller lambdas (diff)
downloadyuzu-b6ae48966d2e914d6c51f62e9eb818fb7aec7c1d.tar.gz
yuzu-b6ae48966d2e914d6c51f62e9eb818fb7aec7c1d.tar.xz
yuzu-b6ae48966d2e914d6c51f62e9eb818fb7aec7c1d.zip
Merge pull request #3032 from ReinUsesLisp/simplify-control-flow-brx
shader/control_flow: Abstract repeated code chunks in BRX tracking
Diffstat (limited to '')
-rw-r--r--src/video_core/shader/control_flow.cpp214
1 files changed, 111 insertions, 103 deletions
diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp
index d47c63d9f..b427ac873 100644
--- a/src/video_core/shader/control_flow.cpp
+++ b/src/video_core/shader/control_flow.cpp
@@ -16,7 +16,9 @@
16#include "video_core/shader/shader_ir.h" 16#include "video_core/shader/shader_ir.h"
17 17
18namespace VideoCommon::Shader { 18namespace VideoCommon::Shader {
19
19namespace { 20namespace {
21
20using Tegra::Shader::Instruction; 22using Tegra::Shader::Instruction;
21using Tegra::Shader::OpCode; 23using Tegra::Shader::OpCode;
22 24
@@ -68,15 +70,15 @@ struct CFGRebuildState {
68 const ProgramCode& program_code; 70 const ProgramCode& program_code;
69 ConstBufferLocker& locker; 71 ConstBufferLocker& locker;
70 u32 start{}; 72 u32 start{};
71 std::vector<BlockInfo> block_info{}; 73 std::vector<BlockInfo> block_info;
72 std::list<u32> inspect_queries{}; 74 std::list<u32> inspect_queries;
73 std::list<Query> queries{}; 75 std::list<Query> queries;
74 std::unordered_map<u32, u32> registered{}; 76 std::unordered_map<u32, u32> registered;
75 std::set<u32> labels{}; 77 std::set<u32> labels;
76 std::map<u32, u32> ssy_labels{}; 78 std::map<u32, u32> ssy_labels;
77 std::map<u32, u32> pbk_labels{}; 79 std::map<u32, u32> pbk_labels;
78 std::unordered_map<u32, BlockStack> stacks{}; 80 std::unordered_map<u32, BlockStack> stacks;
79 ASTManager* manager; 81 ASTManager* manager{};
80}; 82};
81 83
82enum class BlockCollision : u32 { None, Found, Inside }; 84enum class BlockCollision : u32 { None, Found, Inside };
@@ -109,7 +111,7 @@ BlockInfo& CreateBlockInfo(CFGRebuildState& state, u32 start, u32 end) {
109} 111}
110 112
111Pred GetPredicate(u32 index, bool negated) { 113Pred GetPredicate(u32 index, bool negated) {
112 return static_cast<Pred>(index + (negated ? 8 : 0)); 114 return static_cast<Pred>(static_cast<u64>(index) + (negated ? 8ULL : 0ULL));
113} 115}
114 116
115/** 117/**
@@ -136,15 +138,13 @@ struct BranchIndirectInfo {
136 s32 relative_position{}; 138 s32 relative_position{};
137}; 139};
138 140
139std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState& state, 141struct BufferInfo {
140 u32 start_address, u32 current_position) { 142 u32 index;
141 const u32 shader_start = state.start; 143 u32 offset;
142 u32 pos = current_position; 144};
143 BranchIndirectInfo result{};
144 u64 track_register = 0;
145 145
146 // Step 0 Get BRX Info 146std::optional<std::pair<s32, u64>> GetBRXInfo(const CFGRebuildState& state, u32& pos) {
147 const Instruction instr = {state.program_code[pos]}; 147 const Instruction instr = state.program_code[pos];
148 const auto opcode = OpCode::Decode(instr); 148 const auto opcode = OpCode::Decode(instr);
149 if (opcode->get().GetId() != OpCode::Id::BRX) { 149 if (opcode->get().GetId() != OpCode::Id::BRX) {
150 return std::nullopt; 150 return std::nullopt;
@@ -152,86 +152,94 @@ std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState&
152 if (instr.brx.constant_buffer != 0) { 152 if (instr.brx.constant_buffer != 0) {
153 return std::nullopt; 153 return std::nullopt;
154 } 154 }
155 track_register = instr.gpr8.Value(); 155 --pos;
156 result.relative_position = instr.brx.GetBranchExtend(); 156 return std::make_pair(instr.brx.GetBranchExtend(), instr.gpr8.Value());
157 pos--; 157}
158 bool found_track = false;
159 158
160 // Step 1 Track LDC 159template <typename Result, typename TestCallable, typename PackCallable>
161 while (pos >= shader_start) { 160// requires std::predicate<TestCallable, Instruction, const OpCode::Matcher&>
162 if (IsSchedInstruction(pos, shader_start)) { 161// requires std::invocable<PackCallable, Instruction, const OpCode::Matcher&>
163 pos--; 162std::optional<Result> TrackInstruction(const CFGRebuildState& state, u32& pos, TestCallable test,
163 PackCallable pack) {
164 for (; pos >= state.start; --pos) {
165 if (IsSchedInstruction(pos, state.start)) {
164 continue; 166 continue;
165 } 167 }
166 const Instruction instr = {state.program_code[pos]}; 168 const Instruction instr = state.program_code[pos];
167 const auto opcode = OpCode::Decode(instr); 169 const auto opcode = OpCode::Decode(instr);
168 if (opcode->get().GetId() == OpCode::Id::LD_C) { 170 if (!opcode) {
169 if (instr.gpr0.Value() == track_register && 171 continue;
170 instr.ld_c.type.Value() == Tegra::Shader::UniformType::Single) { 172 }
171 result.buffer = instr.cbuf36.index.Value(); 173 if (test(instr, opcode->get())) {
172 result.offset = static_cast<u32>(instr.cbuf36.GetOffset()); 174 --pos;
173 track_register = instr.gpr8.Value(); 175 return std::make_optional(pack(instr, opcode->get()));
174 pos--;
175 found_track = true;
176 break;
177 }
178 } 176 }
179 pos--;
180 } 177 }
178 return std::nullopt;
179}
181 180
182 if (!found_track) { 181std::optional<std::pair<BufferInfo, u64>> TrackLDC(const CFGRebuildState& state, u32& pos,
183 return std::nullopt; 182 u64 brx_tracked_register) {
184 } 183 return TrackInstruction<std::pair<BufferInfo, u64>>(
185 found_track = false; 184 state, pos,
185 [brx_tracked_register](auto instr, const auto& opcode) {
186 return opcode.GetId() == OpCode::Id::LD_C &&
187 instr.gpr0.Value() == brx_tracked_register &&
188 instr.ld_c.type.Value() == Tegra::Shader::UniformType::Single;
189 },
190 [](auto instr, const auto& opcode) {
191 const BufferInfo info = {static_cast<u32>(instr.cbuf36.index.Value()),
192 static_cast<u32>(instr.cbuf36.GetOffset())};
193 return std::make_pair(info, instr.gpr8.Value());
194 });
195}
186 196
187 // Step 2 Track SHL 197std::optional<u64> TrackSHLRegister(const CFGRebuildState& state, u32& pos,
188 while (pos >= shader_start) { 198 u64 ldc_tracked_register) {
189 if (IsSchedInstruction(pos, shader_start)) { 199 return TrackInstruction<u64>(state, pos,
190 pos--; 200 [ldc_tracked_register](auto instr, const auto& opcode) {
191 continue; 201 return opcode.GetId() == OpCode::Id::SHL_IMM &&
192 } 202 instr.gpr0.Value() == ldc_tracked_register;
193 const Instruction instr = state.program_code[pos]; 203 },
194 const auto opcode = OpCode::Decode(instr); 204 [](auto instr, const auto&) { return instr.gpr8.Value(); });
195 if (opcode->get().GetId() == OpCode::Id::SHL_IMM) { 205}
196 if (instr.gpr0.Value() == track_register) { 206
197 track_register = instr.gpr8.Value(); 207std::optional<u32> TrackIMNMXValue(const CFGRebuildState& state, u32& pos,
198 pos--; 208 u64 shl_tracked_register) {
199 found_track = true; 209 return TrackInstruction<u32>(state, pos,
200 break; 210 [shl_tracked_register](auto instr, const auto& opcode) {
201 } 211 return opcode.GetId() == OpCode::Id::IMNMX_IMM &&
202 } 212 instr.gpr0.Value() == shl_tracked_register;
203 pos--; 213 },
214 [](auto instr, const auto&) {
215 return static_cast<u32>(instr.alu.GetSignedImm20_20() + 1);
216 });
217}
218
219std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState& state, u32 pos) {
220 const auto brx_info = GetBRXInfo(state, pos);
221 if (!brx_info) {
222 return std::nullopt;
204 } 223 }
224 const auto [relative_position, brx_tracked_register] = *brx_info;
205 225
206 if (!found_track) { 226 const auto ldc_info = TrackLDC(state, pos, brx_tracked_register);
227 if (!ldc_info) {
207 return std::nullopt; 228 return std::nullopt;
208 } 229 }
209 found_track = false; 230 const auto [buffer_info, ldc_tracked_register] = *ldc_info;
210 231
211 // Step 3 Track IMNMX 232 const auto shl_tracked_register = TrackSHLRegister(state, pos, ldc_tracked_register);
212 while (pos >= shader_start) { 233 if (!shl_tracked_register) {
213 if (IsSchedInstruction(pos, shader_start)) { 234 return std::nullopt;
214 pos--;
215 continue;
216 }
217 const Instruction instr = state.program_code[pos];
218 const auto opcode = OpCode::Decode(instr);
219 if (opcode->get().GetId() == OpCode::Id::IMNMX_IMM) {
220 if (instr.gpr0.Value() == track_register) {
221 track_register = instr.gpr8.Value();
222 result.entries = instr.alu.GetSignedImm20_20() + 1;
223 pos--;
224 found_track = true;
225 break;
226 }
227 }
228 pos--;
229 } 235 }
230 236
231 if (!found_track) { 237 const auto entries = TrackIMNMXValue(state, pos, *shl_tracked_register);
238 if (!entries) {
232 return std::nullopt; 239 return std::nullopt;
233 } 240 }
234 return result; 241
242 return BranchIndirectInfo{buffer_info.index, buffer_info.offset, *entries, relative_position};
235} 243}
236 244
237std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address) { 245std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address) {
@@ -420,30 +428,30 @@ std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address)
420 break; 428 break;
421 } 429 }
422 case OpCode::Id::BRX: { 430 case OpCode::Id::BRX: {
423 auto tmp = TrackBranchIndirectInfo(state, address, offset); 431 const auto tmp = TrackBranchIndirectInfo(state, offset);
424 if (tmp) { 432 if (!tmp) {
425 auto result = *tmp;
426 std::vector<CaseBranch> branches{};
427 s32 pc_target = offset + result.relative_position;
428 for (u32 i = 0; i < result.entries; i++) {
429 auto k = state.locker.ObtainKey(result.buffer, result.offset + i * 4);
430 if (!k) {
431 return {ParseResult::AbnormalFlow, parse_info};
432 }
433 u32 value = *k;
434 u32 target = static_cast<u32>((value >> 3) + pc_target);
435 insert_label(state, target);
436 branches.emplace_back(value, target);
437 }
438 parse_info.end_address = offset;
439 parse_info.branch_info = MakeBranchInfo<MultiBranch>(
440 static_cast<u32>(instr.gpr8.Value()), std::move(branches));
441
442 return {ParseResult::ControlCaught, parse_info};
443 } else {
444 LOG_WARNING(HW_GPU, "BRX Track Unsuccesful"); 433 LOG_WARNING(HW_GPU, "BRX Track Unsuccesful");
434 return {ParseResult::AbnormalFlow, parse_info};
445 } 435 }
446 return {ParseResult::AbnormalFlow, parse_info}; 436
437 const auto result = *tmp;
438 const s32 pc_target = offset + result.relative_position;
439 std::vector<CaseBranch> branches;
440 for (u32 i = 0; i < result.entries; i++) {
441 auto key = state.locker.ObtainKey(result.buffer, result.offset + i * 4);
442 if (!key) {
443 return {ParseResult::AbnormalFlow, parse_info};
444 }
445 u32 value = *key;
446 u32 target = static_cast<u32>((value >> 3) + pc_target);
447 insert_label(state, target);
448 branches.emplace_back(value, target);
449 }
450 parse_info.end_address = offset;
451 parse_info.branch_info = MakeBranchInfo<MultiBranch>(
452 static_cast<u32>(instr.gpr8.Value()), std::move(branches));
453
454 return {ParseResult::ControlCaught, parse_info};
447 } 455 }
448 default: 456 default:
449 break; 457 break;