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