summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2019-10-27 02:24:48 -0300
committerGravatar ReinUsesLisp2019-11-07 01:44:08 -0300
commit46c30472830bd7965027a7c1464d6e0d6ba40796 (patch)
tree0d949d5bde0271cbc81781ab1a21f919584899d6 /src
parentshader/control_flow: Silence Intellisense cast warnings (diff)
downloadyuzu-46c30472830bd7965027a7c1464d6e0d6ba40796.tar.gz
yuzu-46c30472830bd7965027a7c1464d6e0d6ba40796.tar.xz
yuzu-46c30472830bd7965027a7c1464d6e0d6ba40796.zip
shader/control_flow: Abstract repeated code chunks in BRX tracking
Remove copied and pasted for cycles into a common templated function.
Diffstat (limited to 'src')
-rw-r--r--src/video_core/shader/control_flow.cpp194
1 files changed, 101 insertions, 93 deletions
diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp
index 1896abc22..278de4084 100644
--- a/src/video_core/shader/control_flow.cpp
+++ b/src/video_core/shader/control_flow.cpp
@@ -2,6 +2,7 @@
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 <functional>
5#include <list> 6#include <list>
6#include <map> 7#include <map>
7#include <set> 8#include <set>
@@ -16,7 +17,9 @@
16#include "video_core/shader/shader_ir.h" 17#include "video_core/shader/shader_ir.h"
17 18
18namespace VideoCommon::Shader { 19namespace VideoCommon::Shader {
20
19namespace { 21namespace {
22
20using Tegra::Shader::Instruction; 23using Tegra::Shader::Instruction;
21using Tegra::Shader::OpCode; 24using Tegra::Shader::OpCode;
22 25
@@ -136,15 +139,13 @@ struct BranchIndirectInfo {
136 s32 relative_position{}; 139 s32 relative_position{};
137}; 140};
138 141
139std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState& state, 142struct BufferInfo {
140 u32 start_address, u32 current_position) { 143 u32 index;
141 const u32 shader_start = state.start; 144 u32 offset;
142 u32 pos = current_position; 145};
143 BranchIndirectInfo result{};
144 u64 track_register = 0;
145 146
146 // Step 0 Get BRX Info 147std::optional<std::pair<s32, u64>> GetBRXInfo(const CFGRebuildState& state, u32& pos) {
147 const Instruction instr = {state.program_code[pos]}; 148 const Instruction instr = state.program_code[pos];
148 const auto opcode = OpCode::Decode(instr); 149 const auto opcode = OpCode::Decode(instr);
149 if (opcode->get().GetId() != OpCode::Id::BRX) { 150 if (opcode->get().GetId() != OpCode::Id::BRX) {
150 return std::nullopt; 151 return std::nullopt;
@@ -152,86 +153,93 @@ std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState&
152 if (instr.brx.constant_buffer != 0) { 153 if (instr.brx.constant_buffer != 0) {
153 return std::nullopt; 154 return std::nullopt;
154 } 155 }
155 track_register = instr.gpr8.Value(); 156 --pos;
156 result.relative_position = instr.brx.GetBranchExtend(); 157 return std::make_pair(instr.brx.GetBranchExtend(), instr.gpr8.Value());
157 pos--; 158}
158 bool found_track = false;
159 159
160 // Step 1 Track LDC 160template <typename Result>
161 while (pos >= shader_start) { 161std::optional<Result> TrackInstruction(
162 if (IsSchedInstruction(pos, shader_start)) { 162 const CFGRebuildState& state, u32& pos,
163 pos--; 163 std::function<bool(Instruction, const OpCode::Matcher&)>&& test,
164 std::function<Result(Instruction, const OpCode::Matcher&)>&& pack) {
165 for (; pos >= state.start; --pos) {
166 if (IsSchedInstruction(pos, state.start)) {
164 continue; 167 continue;
165 } 168 }
166 const Instruction instr = {state.program_code[pos]}; 169 const Instruction instr = state.program_code[pos];
167 const auto opcode = OpCode::Decode(instr); 170 const auto opcode = OpCode::Decode(instr);
168 if (opcode->get().GetId() == OpCode::Id::LD_C) { 171 if (!opcode) {
169 if (instr.gpr0.Value() == track_register && 172 continue;
170 instr.ld_c.type.Value() == Tegra::Shader::UniformType::Single) { 173 }
171 result.buffer = instr.cbuf36.index.Value(); 174 if (test(instr, opcode->get())) {
172 result.offset = static_cast<u32>(instr.cbuf36.GetOffset()); 175 --pos;
173 track_register = instr.gpr8.Value(); 176 return std::make_optional(pack(instr, opcode->get()));
174 pos--;
175 found_track = true;
176 break;
177 }
178 } 177 }
179 pos--;
180 } 178 }
179 return std::nullopt;
180}
181 181
182 if (!found_track) { 182std::optional<std::pair<BufferInfo, u64>> TrackLDC(const CFGRebuildState& state, u32& pos,
183 return std::nullopt; 183 u64 brx_tracked_register) {
184 } 184 return TrackInstruction<std::pair<BufferInfo, u64>>(
185 found_track = false; 185 state, pos,
186 [brx_tracked_register](auto instr, auto& opcode) {
187 return opcode.GetId() == OpCode::Id::LD_C &&
188 instr.gpr0.Value() == brx_tracked_register &&
189 instr.ld_c.type.Value() == Tegra::Shader::UniformType::Single;
190 },
191 [](auto instr, auto& opcode) {
192 const BufferInfo info = {static_cast<u32>(instr.cbuf36.index.Value()),
193 static_cast<u32>(instr.cbuf36.GetOffset())};
194 return std::make_pair(info, instr.gpr8.Value());
195 });
196}
186 197
187 // Step 2 Track SHL 198std::optional<u64> TrackSHLRegister(const CFGRebuildState& state, u32& pos,
188 while (pos >= shader_start) { 199 u64 ldc_tracked_register) {
189 if (IsSchedInstruction(pos, shader_start)) { 200 return TrackInstruction<u64>(state, pos,
190 pos--; 201 [ldc_tracked_register](auto instr, auto& opcode) {
191 continue; 202 return opcode.GetId() == OpCode::Id::SHL_IMM &&
192 } 203 instr.gpr0.Value() == ldc_tracked_register;
193 const Instruction instr = state.program_code[pos]; 204 },
194 const auto opcode = OpCode::Decode(instr); 205 [](auto instr, auto&) { return instr.gpr8.Value(); });
195 if (opcode->get().GetId() == OpCode::Id::SHL_IMM) { 206}
196 if (instr.gpr0.Value() == track_register) { 207
197 track_register = instr.gpr8.Value(); 208std::optional<u32> TrackIMNMXValue(const CFGRebuildState& state, u32& pos,
198 pos--; 209 u64 shl_tracked_register) {
199 found_track = true; 210 return TrackInstruction<u32>(
200 break; 211 state, pos,
201 } 212 [shl_tracked_register](auto instr, auto& opcode) {
202 } 213 return opcode.GetId() == OpCode::Id::IMNMX_IMM &&
203 pos--; 214 instr.gpr0.Value() == shl_tracked_register;
215 },
216 [](auto instr, auto&) { return static_cast<u32>(instr.alu.GetSignedImm20_20() + 1); });
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;