label-aarch32.h revision f8833fa525b25cb1d72beb4f2d033d5ad9a3eb80
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 Label { 45 public: 46 typedef int32_t Offset; 47 static const Offset kMaxOffset = 0x7fffffff; 48 49 class LabelEmitOperator { 50 Label::Offset max_backward_; 51 Label::Offset max_forward_; 52 53 public: 54 LabelEmitOperator(Label::Offset max_backward, Label::Offset max_forward) 55 : max_backward_(max_backward), max_forward_(max_forward) {} 56 virtual ~LabelEmitOperator() {} 57 virtual uint32_t Encode(uint32_t /*instr*/, 58 Label::Offset /*pc*/, 59 const Label* /*label*/) const { 60 return 0; 61 } 62 Label::Offset GetMaxForwardDistance() const { return max_forward_; } 63 Label::Offset GetMaxBackwardDistance() const { return max_backward_; } 64 }; 65 66 class ForwardReference { 67 public: 68 ForwardReference(int32_t location, const LabelEmitOperator& op, bool t32) 69 : location_(location), op_(op), is_t32_(t32), is_branch_(false) {} 70 Offset GetMaxForwardDistance() const { return op_.GetMaxForwardDistance(); } 71 int32_t GetLocation() const { return location_; } 72 uint32_t GetStatePCOffset() const { 73 return is_t32_ ? kT32PcDelta : kA32PcDelta; 74 } 75 bool IsUsingT32() const { return is_t32_; } 76 bool IsBranch() const { return is_branch_; } 77 void SetIsBranch() { is_branch_ = true; } 78 const LabelEmitOperator& GetEmitOperator() const { return op_; } 79 Offset GetCheckpoint() const { 80 return GetMaxForwardDistance() + (GetLocation() + GetStatePCOffset()); 81 } 82 83 private: 84 int32_t location_; 85 const LabelEmitOperator& op_; 86 bool is_t32_; 87 bool is_branch_; 88 }; 89 90 typedef std::list<ForwardReference> ForwardRefList; 91 92 enum UpdateCheckpointOption { kNoUpdateNecessary, kRecomputeCheckpoint }; 93 94 static bool CompareCheckpoints(const ForwardReference& a, 95 const ForwardReference& b) { 96 return a.GetCheckpoint() < b.GetCheckpoint(); 97 } 98 99 Offset GetNextCheckpoint() { 100 if (IsReferenced()) { 101 ForwardRefList::iterator min_checkpoint = 102 std::min_element(forward_.begin(), 103 forward_.end(), 104 CompareCheckpoints); 105 return (*min_checkpoint).GetCheckpoint(); 106 } 107 return kMaxOffset; 108 } 109 110 public: 111 Label() 112 : imm_offset_(kMaxOffset), 113 pc_offset_(0), 114 is_bound_(false), 115 minus_zero_(false), 116 is_t32_(false), 117 in_veneer_pool_(false), 118 checkpoint_(kMaxOffset) {} 119 explicit Label(Offset offset, uint32_t pc_offset, bool minus_zero = false) 120 : imm_offset_(offset), 121 pc_offset_(pc_offset), 122 is_bound_(true), 123 minus_zero_(minus_zero), 124 is_t32_(false), 125 in_veneer_pool_(false), 126 checkpoint_(kMaxOffset) {} 127 ~Label() {} 128 bool IsBound() const { return is_bound_; } 129 bool IsReferenced() const { return !forward_.empty(); } 130 void Bind(Offset offset, bool isT32) { 131 VIXL_ASSERT(!IsBound()); 132 imm_offset_ = offset; 133 is_bound_ = true; 134 is_t32_ = isT32; 135 } 136 uint32_t GetPcOffset() const { return pc_offset_; } 137 Offset GetLocation() const { 138 VIXL_ASSERT(IsBound()); 139 return imm_offset_ + static_cast<Offset>(pc_offset_); 140 } 141 bool IsUsingT32() const { 142 VIXL_ASSERT(IsBound()); // Must be bound to know if it's a T32 label 143 return is_t32_; 144 } 145 bool IsMinusZero() const { 146 VIXL_ASSERT(IsBound()); 147 return minus_zero_; 148 } 149 bool IsInVeneerPool() const { return in_veneer_pool_; } 150 void SetInVeneerPool() { in_veneer_pool_ = true; } 151 void ResetInVeneerPool() { in_veneer_pool_ = false; } 152 void SetCheckpoint(Offset checkpoint) { checkpoint_ = checkpoint; } 153 Offset GetCheckpoint() const { return checkpoint_; } 154 Offset GetAlignedCheckpoint(int byte_align) const { 155 return AlignDown(GetCheckpoint(), byte_align); 156 } 157 void AddForwardRef(int32_t instr_location, 158 bool isT32, 159 const LabelEmitOperator& op) { 160 forward_.push_back(ForwardReference(instr_location, op, isT32)); 161 } 162 163 ForwardRefList::iterator GetFirstForwardRef() { return forward_.begin(); } 164 ForwardRefList::iterator GetEndForwardRef() { return forward_.end(); } 165 const ForwardReference* GetForwardRefBack() const { 166 if (forward_.empty()) return NULL; 167 return &forward_.back(); 168 } 169 // Erase an item in the list. We don't have to recompute the checkpoint as 170 // the caller does it. 171 ForwardRefList::iterator Erase(ForwardRefList::iterator ref) { 172 return forward_.erase(ref); 173 } 174 ForwardReference& GetBackForwardRef() { return forward_.back(); } 175 176 Offset GetLastInsertForwardDistance() const { 177 if (IsReferenced()) { 178 return forward_.back().GetMaxForwardDistance(); 179 } 180 return kMaxOffset; 181 } 182 183 void ClearForwardRef() { forward_.clear(); } 184 185 // Only used by the literal pool. 186 // Removes the last forward reference, in particular because of a rewind. 187 // TODO(all): This is hard to test as the checkpoint could be affected only 188 // if the literal has multiple forward references. So, the literal has to be 189 // shared between multiple instructions and part of the literal pool which 190 // is not yet supperted. 191 void InvalidateLastForwardReference( 192 UpdateCheckpointOption update_checkpoint = kRecomputeCheckpoint) { 193 if (!IsBound()) { 194 VIXL_ASSERT(IsReferenced()); 195 forward_.pop_back(); 196 } 197 VIXL_ASSERT((update_checkpoint == kNoUpdateNecessary) && 198 ((checkpoint_ == GetNextCheckpoint()) || 199 ((checkpoint_ == Label::kMaxOffset) && forward_.empty()))); 200 if (update_checkpoint == kRecomputeCheckpoint) { 201 checkpoint_ = GetNextCheckpoint(); 202 } 203 } 204 205 // Only used by the literal pool. 206 // Update the checkpoint as the shorter distance from the last 207 // literal in the pool's reference location to the point 208 // where the forward reference will fail. 209 // The last forward reference is assumed to be the one freshly 210 // added regarding this literal. 211 void UpdateCheckpoint() { 212 if (IsReferenced()) { 213 const ForwardReference& ref = forward_.back(); 214 checkpoint_ = std::min(checkpoint_, ref.GetCheckpoint()); 215 } 216 VIXL_ASSERT(GetNextCheckpoint() == checkpoint_); 217 } 218 219 static bool CompareLabels(Label* a, Label* b) { 220 return a->GetCheckpoint() < b->GetCheckpoint(); 221 } 222 223 private: 224 // Once bound, location of this label in the code buffer. 225 Offset imm_offset_; 226 uint32_t pc_offset_; 227 // Is the label bound. 228 bool is_bound_; 229 // Special flag for 'pc - 0'. 230 bool minus_zero_; 231 // Is the label in T32 state. 232 bool is_t32_; 233 // True if the label has been inserted in the veneer pool. 234 bool in_veneer_pool_; 235 // Contains the references to the unbound label 236 ForwardRefList forward_; 237 // Max offset in the code buffer. Must be emitted before this checkpoint. 238 Offset checkpoint_; 239}; 240 241 242} // namespace aarch32 243} // namespace vixl 244 245#endif // VIXL_AARCH32_LABEL_AARCH32_H_ 246