label-aarch32.h revision 7827144797ee5ebfa0b574f45ad8ff235f919304
1// Copyright 2015, VIXL authors 2// All rights reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions are met: 6// 7// * Redistributions of source code must retain the above copyright notice, 8// this list of conditions and the following disclaimer. 9// * Redistributions in binary form must reproduce the above copyright notice, 10// this list of conditions and the following disclaimer in the documentation 11// and/or other materials provided with the distribution. 12// * Neither the name of ARM Limited nor the names of its contributors may be 13// used to endorse or promote products derived from this software without 14// specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27#ifndef VIXL_AARCH32_LABEL_AARCH32_H_ 28#define VIXL_AARCH32_LABEL_AARCH32_H_ 29 30extern "C" { 31#include <stdint.h> 32} 33 34#include <algorithm> 35#include <cstddef> 36#include <iomanip> 37#include <list> 38 39#include "utils-vixl.h" 40 41namespace vixl { 42namespace aarch32 { 43 44class VeneerPoolManager; 45class MacroAssembler; 46 47class Label { 48 public: 49 typedef int32_t Offset; 50 static const Offset kMaxOffset = 0x7fffffff; 51 52 class LabelEmitOperator { 53 Label::Offset max_backward_; 54 Label::Offset max_forward_; 55 56 public: 57 LabelEmitOperator(Label::Offset max_backward, Label::Offset max_forward) 58 : max_backward_(max_backward), max_forward_(max_forward) {} 59 virtual ~LabelEmitOperator() {} 60 virtual uint32_t Encode(uint32_t /*instr*/, 61 Label::Offset /*pc*/, 62 const Label* /*label*/) const { 63 return 0; 64 } 65 Label::Offset GetMaxForwardDistance() const { return max_forward_; } 66 Label::Offset GetMaxBackwardDistance() const { return max_backward_; } 67 }; 68 69 class ForwardReference { 70 public: 71 ForwardReference(int32_t location, const LabelEmitOperator& op, bool t32) 72 : location_(location), op_(op), is_t32_(t32), is_branch_(false) {} 73 Offset GetMaxForwardDistance() const { return op_.GetMaxForwardDistance(); } 74 int32_t GetLocation() const { return location_; } 75 uint32_t GetStatePCOffset() const { 76 return is_t32_ ? kT32PcDelta : kA32PcDelta; 77 } 78 bool IsUsingT32() const { return is_t32_; } 79 bool IsBranch() const { return is_branch_; } 80 void SetIsBranch() { is_branch_ = true; } 81 const LabelEmitOperator& GetEmitOperator() const { return op_; } 82 Offset GetCheckpoint() const { 83 return GetMaxForwardDistance() + (GetLocation() + GetStatePCOffset()); 84 } 85 86 private: 87 int32_t location_; 88 const LabelEmitOperator& op_; 89 bool is_t32_; 90 bool is_branch_; 91 }; 92 93 typedef std::list<ForwardReference> ForwardRefList; 94 95 enum UpdateCheckpointOption { kNoUpdateNecessary, kRecomputeCheckpoint }; 96 97 static bool CompareCheckpoints(const ForwardReference& a, 98 const ForwardReference& b) { 99 return a.GetCheckpoint() < b.GetCheckpoint(); 100 } 101 102 Offset GetNextCheckpoint() { 103 if (IsReferenced()) { 104 ForwardRefList::iterator min_checkpoint = 105 std::min_element(forward_.begin(), 106 forward_.end(), 107 CompareCheckpoints); 108 return (*min_checkpoint).GetCheckpoint(); 109 } 110 return kMaxOffset; 111 } 112 113 public: 114 Label() 115 : imm_offset_(kMaxOffset), 116 pc_offset_(0), 117 is_bound_(false), 118 minus_zero_(false), 119 is_t32_(false), 120 veneer_pool_manager_(NULL), 121 checkpoint_(kMaxOffset) {} 122 explicit Label(Offset offset, uint32_t pc_offset, bool minus_zero = false) 123 : imm_offset_(offset), 124 pc_offset_(pc_offset), 125 is_bound_(true), 126 minus_zero_(minus_zero), 127 is_t32_(false), 128 veneer_pool_manager_(NULL), 129 checkpoint_(kMaxOffset) {} 130 ~Label() {} 131 bool IsBound() const { return is_bound_; } 132 bool IsReferenced() const { return !forward_.empty(); } 133 void Bind(Offset offset, bool isT32) { 134 VIXL_ASSERT(!IsBound()); 135 imm_offset_ = offset; 136 is_bound_ = true; 137 is_t32_ = isT32; 138 } 139 uint32_t GetPcOffset() const { return pc_offset_; } 140 Offset GetLocation() const { 141 VIXL_ASSERT(IsBound()); 142 return imm_offset_ + static_cast<Offset>(pc_offset_); 143 } 144 bool IsUsingT32() const { 145 VIXL_ASSERT(IsBound()); // Must be bound to know if it's a T32 label 146 return is_t32_; 147 } 148 bool IsMinusZero() const { 149 VIXL_ASSERT(IsBound()); 150 return minus_zero_; 151 } 152 bool IsInVeneerPool() const { return veneer_pool_manager_ != NULL; } 153 VeneerPoolManager* GetVeneerPoolManager() const { 154 return veneer_pool_manager_; 155 } 156 void SetVeneerPoolManager(VeneerPoolManager* veneer_pool_manager) { 157 veneer_pool_manager_ = veneer_pool_manager; 158 } 159 void ClearVeneerPoolManager() { veneer_pool_manager_ = NULL; } 160 void SetCheckpoint(Offset checkpoint) { checkpoint_ = checkpoint; } 161 Offset GetCheckpoint() const { return checkpoint_; } 162 Offset GetAlignedCheckpoint(int byte_align) const { 163 return AlignDown(GetCheckpoint(), byte_align); 164 } 165 void AddForwardRef(int32_t instr_location, 166 bool isT32, 167 const LabelEmitOperator& op) { 168 forward_.push_back(ForwardReference(instr_location, op, isT32)); 169 } 170 171 ForwardRefList::iterator GetFirstForwardRef() { return forward_.begin(); } 172 ForwardRefList::iterator GetEndForwardRef() { return forward_.end(); } 173 const ForwardReference* GetForwardRefBack() const { 174 if (forward_.empty()) return NULL; 175 return &forward_.back(); 176 } 177 // Erase an item in the list. We don't have to recompute the checkpoint as 178 // the caller does it. 179 ForwardRefList::iterator Erase(ForwardRefList::iterator ref) { 180 return forward_.erase(ref); 181 } 182 ForwardReference& GetBackForwardRef() { return forward_.back(); } 183 184 Offset GetLastInsertForwardDistance() const { 185 if (IsReferenced()) { 186 return forward_.back().GetMaxForwardDistance(); 187 } 188 return kMaxOffset; 189 } 190 191 void ClearForwardRef() { forward_.clear(); } 192 193 // Only used by the literal pool. 194 // Removes the last forward reference, in particular because of a rewind. 195 // TODO(all): This is hard to test as the checkpoint could be affected only 196 // if the literal has multiple forward references. So, the literal has to be 197 // shared between multiple instructions and part of the literal pool which 198 // is not yet supperted. 199 void InvalidateLastForwardReference( 200 UpdateCheckpointOption update_checkpoint = kRecomputeCheckpoint) { 201 if (!IsBound()) { 202 VIXL_ASSERT(IsReferenced()); 203 forward_.pop_back(); 204 } 205 VIXL_ASSERT((update_checkpoint == kNoUpdateNecessary) && 206 ((checkpoint_ == GetNextCheckpoint()) || 207 ((checkpoint_ == Label::kMaxOffset) && forward_.empty()))); 208 if (update_checkpoint == kRecomputeCheckpoint) { 209 checkpoint_ = GetNextCheckpoint(); 210 } 211 } 212 213 // Only used by the literal pool. 214 // Update the checkpoint as the shorter distance from the last 215 // literal in the pool's reference location to the point 216 // where the forward reference will fail. 217 // The last forward reference is assumed to be the one freshly 218 // added regarding this literal. 219 void UpdateCheckpoint() { 220 if (IsReferenced()) { 221 const ForwardReference& ref = forward_.back(); 222 checkpoint_ = std::min(checkpoint_, ref.GetCheckpoint()); 223 } 224 VIXL_ASSERT(GetNextCheckpoint() == checkpoint_); 225 } 226 227 static bool CompareLabels(Label* a, Label* b) { 228 return a->GetCheckpoint() < b->GetCheckpoint(); 229 } 230 231 private: 232 // Once bound, location of this label in the code buffer. 233 Offset imm_offset_; 234 uint32_t pc_offset_; 235 // Is the label bound. 236 bool is_bound_; 237 // Special flag for 'pc - 0'. 238 bool minus_zero_; 239 // Is the label in T32 state. 240 bool is_t32_; 241 // Not null if the label is currently inserted in the veneer pool. 242 VeneerPoolManager* veneer_pool_manager_; 243 // Contains the references to the unbound label 244 ForwardRefList forward_; 245 // Max offset in the code buffer. Must be emitted before this checkpoint. 246 Offset checkpoint_; 247}; 248 249class VeneerPoolManager { 250 public: 251 explicit VeneerPoolManager(MacroAssembler* masm) 252 : masm_(masm), checkpoint_(Label::kMaxOffset) {} 253 bool IsEmpty() const { return checkpoint_ == Label::kMaxOffset; } 254 Label::Offset GetCheckpoint() const { 255 // Make room for a branch over the pools. 256 return checkpoint_ - kMaxInstructionSizeInBytes; 257 } 258 size_t GetMaxSize() const { 259 return labels_.size() * kMaxInstructionSizeInBytes; 260 } 261 void AddLabel(Label* label); 262 void RemoveLabel(Label* label); 263 void Emit(Label::Offset target); 264 265 private: 266 MacroAssembler* masm_; 267 // List of all unbound labels which are used by a branch instruction. 268 std::list<Label*> labels_; 269 // Max offset in the code buffer where the veneer needs to be emitted. 270 // A default value of Label::kMaxOffset means that the checkpoint is 271 // invalid. 272 Label::Offset checkpoint_; 273}; 274 275} // namespace aarch32 276} // namespace vixl 277 278#endif // VIXL_AARCH32_LABEL_AARCH32_H_ 279