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