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