summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2019-06-26 12:56:03 -0400
committerGravatar FernandoS272019-07-09 08:14:42 -0400
commite7a88f0ab32625c1422583ce63d0f8f20086f7c3 (patch)
tree39e652f3ec8a3c27e424fa2f46c6b8dd4c97e96e /src
parentshader_ir: Correct parsing of scheduling instructions and correct sizing (diff)
downloadyuzu-e7a88f0ab32625c1422583ce63d0f8f20086f7c3.tar.gz
yuzu-e7a88f0ab32625c1422583ce63d0f8f20086f7c3.tar.xz
yuzu-e7a88f0ab32625c1422583ce63d0f8f20086f7c3.zip
control_flow: Address feedback.
Diffstat (limited to 'src')
-rw-r--r--src/video_core/shader/control_flow.cpp126
1 files changed, 37 insertions, 89 deletions
diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp
index 1775dfd81..7b424d65d 100644
--- a/src/video_core/shader/control_flow.cpp
+++ b/src/video_core/shader/control_flow.cpp
@@ -4,6 +4,7 @@
4 4
5#include <list> 5#include <list>
6#include <map> 6#include <map>
7#include <stack>
7#include <unordered_map> 8#include <unordered_map>
8#include <unordered_set> 9#include <unordered_set>
9#include <vector> 10#include <vector>
@@ -20,68 +21,18 @@ using Tegra::Shader::OpCode;
20 21
21constexpr s32 unassigned_branch = -2; 22constexpr s32 unassigned_branch = -2;
22 23
23/**
24 * 'ControlStack' represents a static stack of control jumps such as SSY and PBK
25 * stacks in Maxwell.
26 **/
27struct ControlStack {
28 static constexpr std::size_t stack_fixed_size = 20;
29 std::array<u32, stack_fixed_size> stack{};
30 u32 index{};
31
32 bool Compare(const ControlStack& cs) const {
33 if (index != cs.index) {
34 return false;
35 }
36 return std::memcmp(stack.data(), cs.stack.data(), index * sizeof(u32)) == 0;
37 }
38
39 /// This compare just compares the top of the stack against one another
40 bool SoftCompare(const ControlStack& cs) const {
41 if (index == 0 || cs.index == 0) {
42 return index == cs.index;
43 }
44 return Top() == cs.Top();
45 }
46
47 u32 Size() const {
48 return index;
49 }
50
51 u32 Top() const {
52 return stack[index - 1];
53 }
54
55 bool Push(u32 address) {
56 if (index >= stack.size()) {
57 return false;
58 }
59 stack[index] = address;
60 index++;
61 return true;
62 }
63
64 bool Pop() {
65 if (index == 0) {
66 return false;
67 }
68 index--;
69 return true;
70 }
71};
72
73struct Query { 24struct Query {
74 u32 address{}; 25 u32 address{};
75 ControlStack ssy_stack{}; 26 std::stack<u32> ssy_stack{};
76 ControlStack pbk_stack{}; 27 std::stack<u32> pbk_stack{};
77}; 28};
78 29
79struct BlockStack { 30struct BlockStack {
80 BlockStack() = default; 31 BlockStack() = default;
81 BlockStack(const BlockStack& b) = default; 32 BlockStack(const BlockStack& b) = default;
82 BlockStack(const Query& q) : ssy_stack{q.ssy_stack}, pbk_stack{q.pbk_stack} {} 33 BlockStack(const Query& q) : ssy_stack{q.ssy_stack}, pbk_stack{q.pbk_stack} {}
83 ControlStack ssy_stack{}; 34 std::stack<u32> ssy_stack{};
84 ControlStack pbk_stack{}; 35 std::stack<u32> pbk_stack{};
85}; 36};
86 37
87struct BlockBranchInfo { 38struct BlockBranchInfo {
@@ -144,13 +95,13 @@ struct ParseInfo {
144 u32 end_address{}; 95 u32 end_address{};
145}; 96};
146 97
147BlockInfo* CreateBlockInfo(CFGRebuildState& state, u32 start, u32 end) { 98BlockInfo& CreateBlockInfo(CFGRebuildState& state, u32 start, u32 end) {
148 auto& it = state.block_info.emplace_back(); 99 auto& it = state.block_info.emplace_back();
149 it.start = start; 100 it.start = start;
150 it.end = end; 101 it.end = end;
151 const u32 index = static_cast<u32>(state.block_info.size() - 1); 102 const u32 index = static_cast<u32>(state.block_info.size() - 1);
152 state.registered.insert({start, index}); 103 state.registered.insert({start, index});
153 return &it; 104 return it;
154} 105}
155 106
156Pred GetPredicate(u32 index, bool negated) { 107Pred GetPredicate(u32 index, bool negated) {
@@ -174,16 +125,17 @@ enum class ParseResult : u32 {
174 AbnormalFlow, 125 AbnormalFlow,
175}; 126};
176 127
177ParseResult ParseCode(CFGRebuildState& state, u32 address, ParseInfo& parse_info) { 128std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address) {
178 u32 offset = static_cast<u32>(address); 129 u32 offset = static_cast<u32>(address);
179 const u32 end_address = static_cast<u32>(state.program_size / sizeof(Instruction)); 130 const u32 end_address = static_cast<u32>(state.program_size / sizeof(Instruction));
131 ParseInfo parse_info{};
180 132
181 const auto insert_label = ([](CFGRebuildState& state, u32 address) { 133 const auto insert_label = [](CFGRebuildState& state, u32 address) {
182 auto pair = state.labels.emplace(address); 134 const auto pair = state.labels.emplace(address);
183 if (pair.second) { 135 if (pair.second) {
184 state.inspect_queries.push_back(address); 136 state.inspect_queries.push_back(address);
185 } 137 }
186 }); 138 };
187 139
188 while (true) { 140 while (true) {
189 if (offset >= end_address) { 141 if (offset >= end_address) {
@@ -229,11 +181,11 @@ ParseResult ParseCode(CFGRebuildState& state, u32 address, ParseInfo& parse_info
229 parse_info.branch_info.ignore = false; 181 parse_info.branch_info.ignore = false;
230 parse_info.end_address = offset; 182 parse_info.end_address = offset;
231 183
232 return ParseResult::ControlCaught; 184 return {ParseResult::ControlCaught, parse_info};
233 } 185 }
234 case OpCode::Id::BRA: { 186 case OpCode::Id::BRA: {
235 if (instr.bra.constant_buffer != 0) { 187 if (instr.bra.constant_buffer != 0) {
236 return ParseResult::AbnormalFlow; 188 return {ParseResult::AbnormalFlow, parse_info};
237 } 189 }
238 const auto pred_index = static_cast<u32>(instr.pred.pred_index); 190 const auto pred_index = static_cast<u32>(instr.pred.pred_index);
239 parse_info.branch_info.condition.predicate = 191 parse_info.branch_info.condition.predicate =
@@ -248,7 +200,7 @@ ParseResult ParseCode(CFGRebuildState& state, u32 address, ParseInfo& parse_info
248 offset++; 200 offset++;
249 continue; 201 continue;
250 } 202 }
251 u32 branch_offset = offset + instr.bra.GetBranchTarget(); 203 const u32 branch_offset = offset + instr.bra.GetBranchTarget();
252 if (branch_offset == 0) { 204 if (branch_offset == 0) {
253 parse_info.branch_info.address = exit_branch; 205 parse_info.branch_info.address = exit_branch;
254 } else { 206 } else {
@@ -261,10 +213,9 @@ ParseResult ParseCode(CFGRebuildState& state, u32 address, ParseInfo& parse_info
261 parse_info.branch_info.ignore = false; 213 parse_info.branch_info.ignore = false;
262 parse_info.end_address = offset; 214 parse_info.end_address = offset;
263 215
264 return ParseResult::ControlCaught; 216 return {ParseResult::ControlCaught, parse_info};
265 } 217 }
266 case OpCode::Id::SYNC: { 218 case OpCode::Id::SYNC: {
267 parse_info.branch_info.condition;
268 const auto pred_index = static_cast<u32>(instr.pred.pred_index); 219 const auto pred_index = static_cast<u32>(instr.pred.pred_index);
269 parse_info.branch_info.condition.predicate = 220 parse_info.branch_info.condition.predicate =
270 GetPredicate(pred_index, instr.negate_pred != 0); 221 GetPredicate(pred_index, instr.negate_pred != 0);
@@ -285,10 +236,9 @@ ParseResult ParseCode(CFGRebuildState& state, u32 address, ParseInfo& parse_info
285 parse_info.branch_info.ignore = false; 236 parse_info.branch_info.ignore = false;
286 parse_info.end_address = offset; 237 parse_info.end_address = offset;
287 238
288 return ParseResult::ControlCaught; 239 return {ParseResult::ControlCaught, parse_info};
289 } 240 }
290 case OpCode::Id::BRK: { 241 case OpCode::Id::BRK: {
291 parse_info.branch_info.condition;
292 const auto pred_index = static_cast<u32>(instr.pred.pred_index); 242 const auto pred_index = static_cast<u32>(instr.pred.pred_index);
293 parse_info.branch_info.condition.predicate = 243 parse_info.branch_info.condition.predicate =
294 GetPredicate(pred_index, instr.negate_pred != 0); 244 GetPredicate(pred_index, instr.negate_pred != 0);
@@ -309,10 +259,9 @@ ParseResult ParseCode(CFGRebuildState& state, u32 address, ParseInfo& parse_info
309 parse_info.branch_info.ignore = false; 259 parse_info.branch_info.ignore = false;
310 parse_info.end_address = offset; 260 parse_info.end_address = offset;
311 261
312 return ParseResult::ControlCaught; 262 return {ParseResult::ControlCaught, parse_info};
313 } 263 }
314 case OpCode::Id::KIL: { 264 case OpCode::Id::KIL: {
315 parse_info.branch_info.condition;
316 const auto pred_index = static_cast<u32>(instr.pred.pred_index); 265 const auto pred_index = static_cast<u32>(instr.pred.pred_index);
317 parse_info.branch_info.condition.predicate = 266 parse_info.branch_info.condition.predicate =
318 GetPredicate(pred_index, instr.negate_pred != 0); 267 GetPredicate(pred_index, instr.negate_pred != 0);
@@ -333,7 +282,7 @@ ParseResult ParseCode(CFGRebuildState& state, u32 address, ParseInfo& parse_info
333 parse_info.branch_info.ignore = false; 282 parse_info.branch_info.ignore = false;
334 parse_info.end_address = offset; 283 parse_info.end_address = offset;
335 284
336 return ParseResult::ControlCaught; 285 return {ParseResult::ControlCaught, parse_info};
337 } 286 }
338 case OpCode::Id::SSY: { 287 case OpCode::Id::SSY: {
339 const u32 target = offset + instr.bra.GetBranchTarget(); 288 const u32 target = offset + instr.bra.GetBranchTarget();
@@ -348,7 +297,7 @@ ParseResult ParseCode(CFGRebuildState& state, u32 address, ParseInfo& parse_info
348 break; 297 break;
349 } 298 }
350 case OpCode::Id::BRX: { 299 case OpCode::Id::BRX: {
351 return ParseResult::AbnormalFlow; 300 return {ParseResult::AbnormalFlow, parse_info};
352 } 301 }
353 default: 302 default:
354 break; 303 break;
@@ -360,7 +309,7 @@ ParseResult ParseCode(CFGRebuildState& state, u32 address, ParseInfo& parse_info
360 parse_info.branch_info.is_sync = false; 309 parse_info.branch_info.is_sync = false;
361 parse_info.branch_info.is_brk = false; 310 parse_info.branch_info.is_brk = false;
362 parse_info.end_address = offset - 1; 311 parse_info.end_address = offset - 1;
363 return ParseResult::BlockEnd; 312 return {ParseResult::BlockEnd, parse_info};
364} 313}
365 314
366bool TryInspectAddress(CFGRebuildState& state) { 315bool TryInspectAddress(CFGRebuildState& state) {
@@ -377,10 +326,10 @@ bool TryInspectAddress(CFGRebuildState& state) {
377 case BlockCollision::Inside: { 326 case BlockCollision::Inside: {
378 // This case is the tricky one: 327 // This case is the tricky one:
379 // We need to Split the block in 2 sepparate blocks 328 // We need to Split the block in 2 sepparate blocks
380 auto it = search_result.second; 329 const auto it = search_result.second;
381 BlockInfo* block_info = CreateBlockInfo(state, address, it->end); 330 BlockInfo& block_info = CreateBlockInfo(state, address, it->end);
382 it->end = address - 1; 331 it->end = address - 1;
383 block_info->branch = it->branch; 332 block_info.branch = it->branch;
384 BlockBranchInfo forward_branch{}; 333 BlockBranchInfo forward_branch{};
385 forward_branch.address = address; 334 forward_branch.address = address;
386 forward_branch.ignore = true; 335 forward_branch.ignore = true;
@@ -390,15 +339,14 @@ bool TryInspectAddress(CFGRebuildState& state) {
390 default: 339 default:
391 break; 340 break;
392 } 341 }
393 ParseInfo parse_info; 342 const auto [parse_result, parse_info] = ParseCode(state, address);
394 const ParseResult parse_result = ParseCode(state, address, parse_info);
395 if (parse_result == ParseResult::AbnormalFlow) { 343 if (parse_result == ParseResult::AbnormalFlow) {
396 // if it's AbnormalFlow, we end it as false, ending the CFG reconstruction 344 // if it's AbnormalFlow, we end it as false, ending the CFG reconstruction
397 return false; 345 return false;
398 } 346 }
399 347
400 BlockInfo* block_info = CreateBlockInfo(state, address, parse_info.end_address); 348 BlockInfo& block_info = CreateBlockInfo(state, address, parse_info.end_address);
401 block_info->branch = parse_info.branch_info; 349 block_info.branch = parse_info.branch_info;
402 if (parse_info.branch_info.condition.IsUnconditional()) { 350 if (parse_info.branch_info.condition.IsUnconditional()) {
403 return true; 351 return true;
404 } 352 }
@@ -409,14 +357,15 @@ bool TryInspectAddress(CFGRebuildState& state) {
409} 357}
410 358
411bool TryQuery(CFGRebuildState& state) { 359bool TryQuery(CFGRebuildState& state) {
412 const auto gather_labels = ([](ControlStack& cc, std::map<u32, u32>& labels, BlockInfo& block) { 360 const auto gather_labels = [](std::stack<u32>& cc, std::map<u32, u32>& labels,
361 BlockInfo& block) {
413 auto gather_start = labels.lower_bound(block.start); 362 auto gather_start = labels.lower_bound(block.start);
414 const auto gather_end = labels.upper_bound(block.end); 363 const auto gather_end = labels.upper_bound(block.end);
415 while (gather_start != gather_end) { 364 while (gather_start != gather_end) {
416 cc.Push(gather_start->second); 365 cc.push(gather_start->second);
417 gather_start++; 366 gather_start++;
418 } 367 }
419 }); 368 };
420 if (state.queries.empty()) { 369 if (state.queries.empty()) {
421 return false; 370 return false;
422 } 371 }
@@ -428,9 +377,8 @@ bool TryQuery(CFGRebuildState& state) {
428 // consumes a label. Schedule new queries accordingly 377 // consumes a label. Schedule new queries accordingly
429 if (block.visited) { 378 if (block.visited) {
430 BlockStack& stack = state.stacks[q.address]; 379 BlockStack& stack = state.stacks[q.address];
431 const bool all_okay = 380 const bool all_okay = (stack.ssy_stack.size() == 0 || q.ssy_stack == stack.ssy_stack) &&
432 (stack.ssy_stack.Size() == 0 || q.ssy_stack.Compare(stack.ssy_stack)) && 381 (stack.pbk_stack.size() == 0 || q.pbk_stack == stack.pbk_stack);
433 (stack.pbk_stack.Size() == 0 || q.pbk_stack.Compare(stack.pbk_stack));
434 state.queries.pop_front(); 382 state.queries.pop_front();
435 return all_okay; 383 return all_okay;
436 } 384 }
@@ -447,15 +395,15 @@ bool TryQuery(CFGRebuildState& state) {
447 Query conditional_query{q2}; 395 Query conditional_query{q2};
448 if (block.branch.is_sync) { 396 if (block.branch.is_sync) {
449 if (block.branch.address == unassigned_branch) { 397 if (block.branch.address == unassigned_branch) {
450 block.branch.address = conditional_query.ssy_stack.Top(); 398 block.branch.address = conditional_query.ssy_stack.top();
451 } 399 }
452 conditional_query.ssy_stack.Pop(); 400 conditional_query.ssy_stack.pop();
453 } 401 }
454 if (block.branch.is_brk) { 402 if (block.branch.is_brk) {
455 if (block.branch.address == unassigned_branch) { 403 if (block.branch.address == unassigned_branch) {
456 block.branch.address = conditional_query.pbk_stack.Top(); 404 block.branch.address = conditional_query.pbk_stack.top();
457 } 405 }
458 conditional_query.pbk_stack.Pop(); 406 conditional_query.pbk_stack.pop();
459 } 407 }
460 conditional_query.address = block.branch.address; 408 conditional_query.address = block.branch.address;
461 state.queries.push_back(conditional_query); 409 state.queries.push_back(conditional_query);