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