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
35namespace r600 {
36
37using std::stack;
38using std::vector;
39using std::shared_ptr;
40
41struct StackFrame {
42
43   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
58using PStackFrame = shared_ptr<StackFrame>;
59
60struct 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
66struct 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
72struct ConditionalJumpTrackerImpl {
73   ConditionalJumpTrackerImpl();
74   stack<PStackFrame> m_jump_stack;
75   stack<PStackFrame> m_loop_stack;
76   int m_current_loop_stack_pos;
77};
78
79ConditionalJumpTrackerImpl::ConditionalJumpTrackerImpl():
80   m_current_loop_stack_pos(0)
81{
82
83}
84
85ConditionalJumpTracker::~ConditionalJumpTracker()
86{
87   delete impl;
88}
89
90ConditionalJumpTracker::ConditionalJumpTracker()
91{
92   impl = new ConditionalJumpTrackerImpl();
93}
94
95void 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
110bool 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
126bool 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
149IfFrame::IfFrame(r600_bytecode_cf *s):
150   StackFrame (s, jt_if)
151{
152}
153
154StackFrame::~StackFrame()
155{
156}
157
158void IfFrame::fixup_mid(r600_bytecode_cf *source)
159{
160   /* JUMP target is ELSE */
161   start->cf_addr = source->id;
162}
163
164void 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
173LoopFrame::LoopFrame(r600_bytecode_cf *s):
174   StackFrame(s, jt_loop)
175{
176}
177
178void LoopFrame::fixup_mid(UNUSED r600_bytecode_cf *mid)
179{
180}
181
182void 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