1 /* -*- mesa-c++ -*-
2 *
3 * Copyright (c) 2019 Collabora LTD
4 *
5 * Author: Gert Wollny <gert.wollny@collabora.com>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * on the rights to use, copy, modify, merge, publish, distribute, sub
11 * license, and/or sell copies of the Software, and to permit persons to whom
12 * the Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
16 * Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 * USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27 #include "sfn_conditionaljumptracker.h"
28
29 #include "sfn_debug.h"
30
31 #include <iostream>
32 #include <memory>
33 #include <stack>
34 #include <vector>
35
36 namespace r600 {
37
38 using std::shared_ptr;
39 using std::stack;
40 using std::vector;
41
42 struct StackFrame {
43
StackFramer600::StackFrame44 StackFrame(r600_bytecode_cf *s, JumpType t):
45 type(t),
46 start(s)
47 {
48 }
49
50 virtual ~StackFrame();
51
52 JumpType type;
53 r600_bytecode_cf *start;
54 vector<r600_bytecode_cf *> mid;
55
56 virtual void fixup_mid(r600_bytecode_cf *cf) = 0;
57 virtual void fixup_pop(r600_bytecode_cf *final) = 0;
58 };
59
60 using PStackFrame = shared_ptr<StackFrame>;
61
62 struct IfFrame : public StackFrame {
63 IfFrame(r600_bytecode_cf *s);
64 void fixup_mid(r600_bytecode_cf *cf) override;
65 void fixup_pop(r600_bytecode_cf *final) override;
66 };
67
68 struct LoopFrame : public StackFrame {
69 LoopFrame(r600_bytecode_cf *s);
70 void fixup_mid(r600_bytecode_cf *cf) override;
71 void fixup_pop(r600_bytecode_cf *final) override;
72 };
73
74 struct ConditionalJumpTrackerImpl {
75 ConditionalJumpTrackerImpl();
76 stack<PStackFrame> m_jump_stack;
77 stack<PStackFrame> m_loop_stack;
78 int m_current_loop_stack_pos;
79 };
80
ConditionalJumpTrackerImpl()81 ConditionalJumpTrackerImpl::ConditionalJumpTrackerImpl():
82 m_current_loop_stack_pos(0)
83 {
84 }
85
~ConditionalJumpTracker()86 ConditionalJumpTracker::~ConditionalJumpTracker() { delete impl; }
87
ConditionalJumpTracker()88 ConditionalJumpTracker::ConditionalJumpTracker()
89 {
90 impl = new ConditionalJumpTrackerImpl();
91 }
92
93 void
push(r600_bytecode_cf * start,JumpType type)94 ConditionalJumpTracker::push(r600_bytecode_cf *start, JumpType type)
95 {
96 PStackFrame f;
97 switch (type) {
98 case jt_if:
99 f.reset(new IfFrame(start));
100 break;
101 case jt_loop:
102 f.reset(new LoopFrame(start));
103 impl->m_loop_stack.push(f);
104 break;
105 }
106 impl->m_jump_stack.push(f);
107 }
108
109 bool
pop(r600_bytecode_cf * final,JumpType type)110 ConditionalJumpTracker::pop(r600_bytecode_cf *final, JumpType type)
111 {
112 if (impl->m_jump_stack.empty())
113 return false;
114
115 auto& frame = *impl->m_jump_stack.top();
116 if (frame.type != type)
117 return false;
118
119 frame.fixup_pop(final);
120 if (frame.type == jt_loop)
121 impl->m_loop_stack.pop();
122 impl->m_jump_stack.pop();
123 return true;
124 }
125
126 bool
add_mid(r600_bytecode_cf * source,JumpType type)127 ConditionalJumpTracker::add_mid(r600_bytecode_cf *source, JumpType type)
128 {
129 if (impl->m_jump_stack.empty()) {
130 sfn_log << "Jump stack empty\n";
131 return false;
132 }
133
134 PStackFrame pframe;
135 if (type == jt_loop) {
136 if (impl->m_loop_stack.empty()) {
137 sfn_log << "Loop jump stack empty\n";
138 return false;
139 }
140 pframe = impl->m_loop_stack.top();
141 } else {
142 pframe = impl->m_jump_stack.top();
143 }
144
145 pframe->mid.push_back(source);
146 pframe->fixup_mid(source);
147 return true;
148 }
149
IfFrame(r600_bytecode_cf * s)150 IfFrame::IfFrame(r600_bytecode_cf *s):
151 StackFrame(s, jt_if)
152 {
153 }
154
~StackFrame()155 StackFrame::~StackFrame() {}
156
157 void
fixup_mid(r600_bytecode_cf * source)158 IfFrame::fixup_mid(r600_bytecode_cf *source)
159 {
160 /* JUMP target is ELSE */
161 start->cf_addr = source->id;
162 }
163
164 void
fixup_pop(r600_bytecode_cf * final)165 IfFrame::fixup_pop(r600_bytecode_cf *final)
166 {
167 /* JUMP or ELSE target is one past last CF instruction */
168 unsigned offset = final->eg_alu_extended ? 4 : 2;
169 auto src = mid.empty() ? start : mid[0];
170 src->cf_addr = final->id + offset;
171 src->pop_count = 1;
172 }
173
LoopFrame(r600_bytecode_cf * s)174 LoopFrame::LoopFrame(r600_bytecode_cf *s):
175 StackFrame(s, jt_loop)
176 {
177 }
178
179 void
fixup_mid(UNUSED r600_bytecode_cf * mid)180 LoopFrame::fixup_mid(UNUSED r600_bytecode_cf *mid)
181 {
182 }
183
184 void
fixup_pop(r600_bytecode_cf * final)185 LoopFrame::fixup_pop(r600_bytecode_cf *final)
186 {
187 /* LOOP END address is past LOOP START */
188 final->cf_addr = start->id + 2;
189
190 /* LOOP START address is past LOOP END*/
191 start->cf_addr = final->id + 2;
192
193 /* BREAK and CONTINUE point at LOOP END*/
194 for (auto m : mid)
195 m->cf_addr = final->id;
196 }
197
198 } // namespace r600
199