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