• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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