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 #include "sfn_debug.h"
29
30 #include <stack>
31 #include <vector>
32 #include <memory>
33 #include <iostream>
34
35 namespace r600 {
36
37 using std::stack;
38 using std::vector;
39 using std::shared_ptr;
40
41 struct StackFrame {
42
StackFramer600::StackFrame43 StackFrame(r600_bytecode_cf *s, JumpType t):
44 type(t),
45 start(s)
46 {}
47
48 virtual ~StackFrame();
49
50 JumpType type;
51 r600_bytecode_cf *start;
52 vector<r600_bytecode_cf *> mid;
53
54 virtual void fixup_mid(r600_bytecode_cf *cf) = 0;
55 virtual void fixup_pop(r600_bytecode_cf *final) = 0;
56 };
57
58 using PStackFrame = shared_ptr<StackFrame>;
59
60 struct IfFrame : public StackFrame {
61 IfFrame(r600_bytecode_cf *s);
62 void fixup_mid(r600_bytecode_cf *cf) override;
63 void fixup_pop(r600_bytecode_cf *final) override;
64 };
65
66 struct LoopFrame : public StackFrame {
67 LoopFrame(r600_bytecode_cf *s);
68 void fixup_mid(r600_bytecode_cf *cf) override;
69 void fixup_pop(r600_bytecode_cf *final) override;
70 };
71
72 struct ConditionalJumpTrackerImpl {
73 ConditionalJumpTrackerImpl();
74 stack<PStackFrame> m_jump_stack;
75 stack<PStackFrame> m_loop_stack;
76 int m_current_loop_stack_pos;
77 };
78
ConditionalJumpTrackerImpl()79 ConditionalJumpTrackerImpl::ConditionalJumpTrackerImpl():
80 m_current_loop_stack_pos(0)
81 {
82
83 }
84
~ConditionalJumpTracker()85 ConditionalJumpTracker::~ConditionalJumpTracker()
86 {
87 delete impl;
88 }
89
ConditionalJumpTracker()90 ConditionalJumpTracker::ConditionalJumpTracker()
91 {
92 impl = new ConditionalJumpTrackerImpl();
93 }
94
push(r600_bytecode_cf * start,JumpType type)95 void ConditionalJumpTracker::push(r600_bytecode_cf *start, JumpType type)
96 {
97 PStackFrame f;
98 switch (type) {
99 case jt_if:
100 f.reset(new IfFrame(start));
101 break;
102 case jt_loop:
103 f.reset(new LoopFrame(start));
104 impl->m_loop_stack.push(f);
105 break;
106 }
107 impl->m_jump_stack.push(f);
108 }
109
pop(r600_bytecode_cf * final,JumpType type)110 bool 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
add_mid(r600_bytecode_cf * source,JumpType type)126 bool ConditionalJumpTracker::add_mid(r600_bytecode_cf *source, JumpType type)
127 {
128 if (impl->m_jump_stack.empty()) {
129 sfn_log << "Jump stack empty\n";
130 return false;
131 }
132
133 PStackFrame pframe;
134 if (type == jt_loop) {
135 if (impl->m_loop_stack.empty()) {
136 sfn_log << "Loop jump stack empty\n";
137 return false;
138 }
139 pframe = impl->m_loop_stack.top();
140 } else {
141 pframe = impl->m_jump_stack.top();
142 }
143
144 pframe->mid.push_back(source);
145 pframe->fixup_mid(source);
146 return true;
147 }
148
IfFrame(r600_bytecode_cf * s)149 IfFrame::IfFrame(r600_bytecode_cf *s):
150 StackFrame (s, jt_if)
151 {
152 }
153
~StackFrame()154 StackFrame::~StackFrame()
155 {
156 }
157
fixup_mid(r600_bytecode_cf * source)158 void IfFrame::fixup_mid(r600_bytecode_cf *source)
159 {
160 /* JUMP target is ELSE */
161 start->cf_addr = source->id;
162 }
163
fixup_pop(r600_bytecode_cf * final)164 void IfFrame::fixup_pop(r600_bytecode_cf *final)
165 {
166 /* JUMP or ELSE target is one past last CF instruction */
167 unsigned offset = final->eg_alu_extended ? 4 : 2;
168 auto src = mid.empty() ? start : mid[0];
169 src->cf_addr = final->id + offset;
170 src->pop_count = 1;
171 }
172
LoopFrame(r600_bytecode_cf * s)173 LoopFrame::LoopFrame(r600_bytecode_cf *s):
174 StackFrame(s, jt_loop)
175 {
176 }
177
fixup_mid(UNUSED r600_bytecode_cf * mid)178 void LoopFrame::fixup_mid(UNUSED r600_bytecode_cf *mid)
179 {
180 }
181
fixup_pop(r600_bytecode_cf * final)182 void LoopFrame::fixup_pop(r600_bytecode_cf *final)
183 {
184 /* LOOP END address is past LOOP START */
185 final->cf_addr = start->id + 2;
186
187 /* LOOP START address is past LOOP END*/
188 start->cf_addr = final->id + 2;
189
190 /* BREAK and CONTINUE point at LOOP END*/
191 for (auto m : mid)
192 m->cf_addr = final->id;
193 }
194
195 }
196