1 /* -*- mesa-c++ -*-
2 * Copyright 2019 Collabora LTD
3 * Author: Gert Wollny <[email protected]>
4 * SPDX-License-Identifier: MIT
5 */
6
7 #include "sfn_conditionaljumptracker.h"
8
9 #include "sfn_debug.h"
10
11 #include <iostream>
12 #include <memory>
13 #include <stack>
14 #include <vector>
15
16 namespace r600 {
17
18 using std::shared_ptr;
19 using std::stack;
20 using std::vector;
21
22 struct StackFrame {
23
StackFramer600::StackFrame24 StackFrame(r600_bytecode_cf *s, JumpType t):
25 type(t),
26 start(s)
27 {
28 }
29
30 virtual ~StackFrame();
31
32 JumpType type;
33 r600_bytecode_cf *start;
34 vector<r600_bytecode_cf *> mid;
35
36 virtual void fixup_mid(r600_bytecode_cf *cf) = 0;
37 virtual void fixup_pop(r600_bytecode_cf *final) = 0;
38 };
39
40 using PStackFrame = shared_ptr<StackFrame>;
41
42 struct IfFrame : public StackFrame {
43 IfFrame(r600_bytecode_cf *s);
44 void fixup_mid(r600_bytecode_cf *cf) override;
45 void fixup_pop(r600_bytecode_cf *final) override;
46 };
47
48 struct LoopFrame : public StackFrame {
49 LoopFrame(r600_bytecode_cf *s);
50 void fixup_mid(r600_bytecode_cf *cf) override;
51 void fixup_pop(r600_bytecode_cf *final) override;
52 };
53
54 struct ConditionalJumpTrackerImpl {
55 ConditionalJumpTrackerImpl();
56 stack<PStackFrame> m_jump_stack;
57 stack<PStackFrame> m_loop_stack;
58 int m_current_loop_stack_pos;
59 };
60
ConditionalJumpTrackerImpl()61 ConditionalJumpTrackerImpl::ConditionalJumpTrackerImpl():
62 m_current_loop_stack_pos(0)
63 {
64 }
65
~ConditionalJumpTracker()66 ConditionalJumpTracker::~ConditionalJumpTracker() { delete impl; }
67
ConditionalJumpTracker()68 ConditionalJumpTracker::ConditionalJumpTracker()
69 {
70 impl = new ConditionalJumpTrackerImpl();
71 }
72
73 void
push(r600_bytecode_cf * start,JumpType type)74 ConditionalJumpTracker::push(r600_bytecode_cf *start, JumpType type)
75 {
76 PStackFrame f;
77 switch (type) {
78 case jt_if:
79 f.reset(new IfFrame(start));
80 break;
81 case jt_loop:
82 f.reset(new LoopFrame(start));
83 impl->m_loop_stack.push(f);
84 break;
85 }
86 impl->m_jump_stack.push(f);
87 }
88
89 bool
pop(r600_bytecode_cf * final,JumpType type)90 ConditionalJumpTracker::pop(r600_bytecode_cf *final, JumpType type)
91 {
92 if (impl->m_jump_stack.empty())
93 return false;
94
95 auto& frame = *impl->m_jump_stack.top();
96 if (frame.type != type)
97 return false;
98
99 frame.fixup_pop(final);
100 if (frame.type == jt_loop)
101 impl->m_loop_stack.pop();
102 impl->m_jump_stack.pop();
103 return true;
104 }
105
106 bool
add_mid(r600_bytecode_cf * source,JumpType type)107 ConditionalJumpTracker::add_mid(r600_bytecode_cf *source, JumpType type)
108 {
109 if (impl->m_jump_stack.empty()) {
110 sfn_log << "Jump stack empty\n";
111 return false;
112 }
113
114 PStackFrame pframe;
115 if (type == jt_loop) {
116 if (impl->m_loop_stack.empty()) {
117 sfn_log << "Loop jump stack empty\n";
118 return false;
119 }
120 pframe = impl->m_loop_stack.top();
121 } else {
122 pframe = impl->m_jump_stack.top();
123 }
124
125 pframe->mid.push_back(source);
126 pframe->fixup_mid(source);
127 return true;
128 }
129
IfFrame(r600_bytecode_cf * s)130 IfFrame::IfFrame(r600_bytecode_cf *s):
131 StackFrame(s, jt_if)
132 {
133 }
134
~StackFrame()135 StackFrame::~StackFrame() {}
136
137 void
fixup_mid(r600_bytecode_cf * source)138 IfFrame::fixup_mid(r600_bytecode_cf *source)
139 {
140 /* JUMP target is ELSE */
141 start->cf_addr = source->id;
142 }
143
144 void
fixup_pop(r600_bytecode_cf * final)145 IfFrame::fixup_pop(r600_bytecode_cf *final)
146 {
147 /* JUMP or ELSE target is one past last CF instruction */
148 unsigned offset = final->eg_alu_extended ? 4 : 2;
149 auto src = mid.empty() ? start : mid[0];
150 src->cf_addr = final->id + offset;
151 src->pop_count = 1;
152 }
153
LoopFrame(r600_bytecode_cf * s)154 LoopFrame::LoopFrame(r600_bytecode_cf *s):
155 StackFrame(s, jt_loop)
156 {
157 }
158
159 void
fixup_mid(UNUSED r600_bytecode_cf * mid)160 LoopFrame::fixup_mid(UNUSED r600_bytecode_cf *mid)
161 {
162 }
163
164 void
fixup_pop(r600_bytecode_cf * final)165 LoopFrame::fixup_pop(r600_bytecode_cf *final)
166 {
167 /* LOOP END address is past LOOP START */
168 final->cf_addr = start->id + 2;
169
170 /* LOOP START address is past LOOP END*/
171 start->cf_addr = final->id + 2;
172
173 /* BREAK and CONTINUE point at LOOP END*/
174 for (auto m : mid)
175 m->cf_addr = final->id;
176 }
177
178 } // namespace r600
179