1 // Copyright 2017, 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
30 extern "C" {
31 #include <stdint.h>
32 }
33
34 #include <algorithm>
35 #include <cstddef>
36 #include <iomanip>
37 #include <list>
38
39 #include "invalset-vixl.h"
40 #include "pool-manager.h"
41 #include "utils-vixl.h"
42
43 #include "constants-aarch32.h"
44 #include "instructions-aarch32.h"
45
46 namespace vixl {
47
48 namespace aarch32 {
49
50 class MacroAssembler;
51
52 class Location : public LocationBase<int32_t> {
53 friend class Assembler;
54 friend class MacroAssembler;
55
56 public:
57 // Unbound location that can be used with the assembler bind() method and
58 // with the assembler methods for generating instructions, but will never
59 // be handled by the pool manager.
Location()60 Location()
61 : LocationBase<int32_t>(kRawLocation, 1 /* placeholder size*/),
62 referenced_(false) {}
63
64 typedef int32_t Offset;
65
~Location()66 ~Location() VIXL_NEGATIVE_TESTING_ALLOW_EXCEPTION {
67 #ifdef VIXL_DEBUG
68 if (IsReferenced() && !IsBound()) {
69 VIXL_ABORT_WITH_MSG("Location, label or literal used but not bound.\n");
70 }
71 #endif
72 }
73
74 Location(Location&&) = default; // movable
75
IsReferenced()76 bool IsReferenced() const { return referenced_; }
77
78 private:
79 class EmitOperator {
80 public:
EmitOperator(InstructionSet isa)81 explicit EmitOperator(InstructionSet isa) : isa_(isa) {
82 #if defined(VIXL_INCLUDE_TARGET_A32_ONLY)
83 USE(isa_);
84 VIXL_ASSERT(isa == A32);
85 #elif defined(VIXL_INCLUDE_TARGET_T32_ONLY)
86 USE(isa_);
87 VIXL_ASSERT(isa == T32);
88 #endif
89 }
~EmitOperator()90 virtual ~EmitOperator() {}
Encode(uint32_t,Location::Offset,const Location *)91 virtual uint32_t Encode(uint32_t /*instr*/,
92 Location::Offset /*pc*/,
93 const Location* /*label*/) const {
94 return 0;
95 }
96 #if defined(VIXL_INCLUDE_TARGET_A32_ONLY)
IsUsingT32()97 bool IsUsingT32() const { return false; }
98 #elif defined(VIXL_INCLUDE_TARGET_T32_ONLY)
IsUsingT32()99 bool IsUsingT32() const { return true; }
100 #else
IsUsingT32()101 bool IsUsingT32() const { return isa_ == T32; }
102 #endif
103
104 private:
105 InstructionSet isa_;
106 };
107
108 protected:
109 class ForwardRef : public ForwardReference<int32_t> {
110 public:
111 // Default constructor for InvalSet.
ForwardRef()112 ForwardRef() : ForwardReference<int32_t>(0, 0, 0, 0, 1), op_(NULL) {}
113
114 ForwardRef(const Location::EmitOperator* op,
115 int32_t location,
116 int size,
117 int32_t min_object_location,
118 int32_t max_object_location,
119 int object_alignment = 1)
120 : ForwardReference<int32_t>(location,
121 size,
122 min_object_location,
123 max_object_location,
124 object_alignment),
125 op_(op) {}
126
op()127 const Location::EmitOperator* op() const { return op_; }
128
129 // We must provide comparison operators to work with InvalSet.
130 bool operator==(const ForwardRef& other) const {
131 return GetLocation() == other.GetLocation();
132 }
133 bool operator<(const ForwardRef& other) const {
134 return GetLocation() < other.GetLocation();
135 }
136 bool operator<=(const ForwardRef& other) const {
137 return GetLocation() <= other.GetLocation();
138 }
139 bool operator>(const ForwardRef& other) const {
140 return GetLocation() > other.GetLocation();
141 }
142
143 private:
144 const Location::EmitOperator* op_;
145 };
146
147 static const int kNPreallocatedElements = 4;
148 // The following parameters will not affect ForwardRefList in practice, as we
149 // resolve all references at once and clear the list, so we do not need to
150 // remove individual elements by invalidating them.
151 static const int32_t kInvalidLinkKey = INT32_MAX;
152 static const size_t kReclaimFrom = 512;
153 static const size_t kReclaimFactor = 2;
154
155 typedef InvalSet<ForwardRef,
156 kNPreallocatedElements,
157 int32_t,
158 kInvalidLinkKey,
159 kReclaimFrom,
160 kReclaimFactor>
161 ForwardRefListBase;
162 typedef InvalSetIterator<ForwardRefListBase> ForwardRefListIteratorBase;
163
164 class ForwardRefList : public ForwardRefListBase {
165 public:
ForwardRefList()166 ForwardRefList() : ForwardRefListBase() {}
167
168 using ForwardRefListBase::Back;
169 using ForwardRefListBase::Front;
170 };
171
172 class ForwardRefListIterator : public ForwardRefListIteratorBase {
173 public:
ForwardRefListIterator(Location * location)174 explicit ForwardRefListIterator(Location* location)
175 : ForwardRefListIteratorBase(&location->forward_) {}
176
177 // TODO: Remove these and use the STL-like interface instead. We'll need a
178 // const_iterator implemented for this.
179 using ForwardRefListIteratorBase::Advance;
180 using ForwardRefListIteratorBase::Current;
181 };
182
183 // For InvalSet::GetKey() and InvalSet::SetKey().
184 friend class InvalSet<ForwardRef,
185 kNPreallocatedElements,
186 int32_t,
187 kInvalidLinkKey,
188 kReclaimFrom,
189 kReclaimFactor>;
190
191 private:
192 virtual void ResolveReferences(internal::AssemblerBase* assembler)
193 VIXL_OVERRIDE;
194
SetReferenced()195 void SetReferenced() { referenced_ = true; }
196
HasForwardReferences()197 bool HasForwardReferences() const { return !forward_.empty(); }
198
GetLastForwardReference()199 ForwardRef GetLastForwardReference() const {
200 VIXL_ASSERT(HasForwardReferences());
201 return forward_.Back();
202 }
203
204 // Add forward reference to this object. Called from the assembler.
205 void AddForwardRef(int32_t instr_location,
206 const EmitOperator& op,
207 const ReferenceInfo* info);
208
209 // Check if we need to add padding when binding this object, in order to
210 // meet the minimum location requirement.
211 bool Needs16BitPadding(int location) const;
212
213 void EncodeLocationFor(internal::AssemblerBase* assembler,
214 int32_t from,
215 const Location::EmitOperator* encoder);
216
217 // True if the label has been used at least once.
218 bool referenced_;
219
220 protected:
221 // Types passed to LocationBase. Must be distinct for unbound Locations (not
222 // relevant for bound locations, as they don't have a corresponding
223 // PoolObject).
224 static const int kRawLocation = 0; // Will not be used by the pool manager.
225 static const int kVeneerType = 1;
226 static const int kLiteralType = 2;
227
228 // Contains the references to the unbound label
229 ForwardRefList forward_;
230
231 // To be used only by derived classes.
Location(uint32_t type,int size,int alignment)232 Location(uint32_t type, int size, int alignment)
233 : LocationBase<int32_t>(type, size, alignment), referenced_(false) {}
234
235 // To be used only by derived classes.
Location(Offset location)236 explicit Location(Offset location)
237 : LocationBase<int32_t>(location), referenced_(false) {}
238
239 virtual int GetMaxAlignment() const VIXL_OVERRIDE;
240 virtual int GetMinLocation() const VIXL_OVERRIDE;
241
242 private:
243 // Included to make the class concrete, however should never be called.
EmitPoolObject(MacroAssemblerInterface * masm)244 virtual void EmitPoolObject(MacroAssemblerInterface* masm) VIXL_OVERRIDE {
245 USE(masm);
246 VIXL_UNREACHABLE();
247 }
248 };
249
250 class Label : public Location {
251 static const int kVeneerSize = 4;
252 // Use an alignment of 1 for all architectures. Even though we can bind an
253 // unused label, because of the way the MacroAssembler works we can always be
254 // sure to have the correct buffer alignment for the instruction set we are
255 // using, so we do not need to enforce additional alignment requirements
256 // here.
257 // TODO: Consider modifying the interface of the pool manager to pass an
258 // optional additional alignment to Bind() in order to handle cases where the
259 // buffer could be unaligned.
260 static const int kVeneerAlignment = 1;
261
262 public:
Label()263 Label() : Location(kVeneerType, kVeneerSize, kVeneerAlignment) {}
Label(Offset location)264 explicit Label(Offset location) : Location(location) {}
265
266 private:
ShouldBeDeletedOnPlacementByPoolManager()267 virtual bool ShouldBeDeletedOnPlacementByPoolManager() const VIXL_OVERRIDE {
268 return false;
269 }
ShouldDeletePoolObjectOnPlacement()270 virtual bool ShouldDeletePoolObjectOnPlacement() const VIXL_OVERRIDE {
271 return false;
272 }
273
274 virtual void UpdatePoolObject(PoolObject<int32_t>* object) VIXL_OVERRIDE;
275 virtual void EmitPoolObject(MacroAssemblerInterface* masm) VIXL_OVERRIDE;
276
UsePoolObjectEmissionMargin()277 virtual bool UsePoolObjectEmissionMargin() const VIXL_OVERRIDE {
278 return true;
279 }
GetPoolObjectEmissionMargin()280 virtual int32_t GetPoolObjectEmissionMargin() const VIXL_OVERRIDE {
281 VIXL_ASSERT(UsePoolObjectEmissionMargin() == true);
282 return 1 * KBytes;
283 }
284 };
285
286 class RawLiteral : public Location {
287 // Some load instructions require alignment to 4 bytes. Since we do
288 // not know what instructions will reference a literal after we place
289 // it, we enforce a 4 byte alignment for literals that are 4 bytes or
290 // larger.
291 static const int kLiteralAlignment = 4;
292
293 public:
294 enum PlacementPolicy { kPlacedWhenUsed, kManuallyPlaced };
295
296 enum DeletionPolicy {
297 kDeletedOnPlacementByPool,
298 kDeletedOnPoolDestruction,
299 kManuallyDeleted
300 };
301
302 RawLiteral(const void* addr,
303 int size,
304 PlacementPolicy placement_policy = kPlacedWhenUsed,
305 DeletionPolicy deletion_policy = kManuallyDeleted)
306 : Location(kLiteralType,
307 size,
308 (size < kLiteralAlignment) ? size : kLiteralAlignment),
309 addr_(addr),
310 manually_placed_(placement_policy == kManuallyPlaced),
311 deletion_policy_(deletion_policy) {
312 // We can't have manually placed literals that are not manually deleted.
313 VIXL_ASSERT(!IsManuallyPlaced() ||
314 (GetDeletionPolicy() == kManuallyDeleted));
315 }
RawLiteral(const void * addr,int size,DeletionPolicy deletion_policy)316 RawLiteral(const void* addr, int size, DeletionPolicy deletion_policy)
317 : Location(kLiteralType,
318 size,
319 (size < kLiteralAlignment) ? size : kLiteralAlignment),
320 addr_(addr),
321 manually_placed_(false),
322 deletion_policy_(deletion_policy) {}
323
324 // noncopyable to avoid one instruction appearing to refer to two or more literals
325 RawLiteral(const RawLiteral&) = delete;
326
327 RawLiteral(RawLiteral &&) = default; // movable
328
GetDataAddress()329 const void* GetDataAddress() const { return addr_; }
GetSize()330 int GetSize() const { return GetPoolObjectSizeInBytes(); }
331
IsManuallyPlaced()332 bool IsManuallyPlaced() const { return manually_placed_; }
333
334 private:
GetDeletionPolicy()335 DeletionPolicy GetDeletionPolicy() const { return deletion_policy_; }
336
ShouldBeDeletedOnPlacementByPoolManager()337 virtual bool ShouldBeDeletedOnPlacementByPoolManager() const VIXL_OVERRIDE {
338 return GetDeletionPolicy() == kDeletedOnPlacementByPool;
339 }
ShouldBeDeletedOnPoolManagerDestruction()340 virtual bool ShouldBeDeletedOnPoolManagerDestruction() const VIXL_OVERRIDE {
341 return GetDeletionPolicy() == kDeletedOnPoolDestruction;
342 }
343 virtual void EmitPoolObject(MacroAssemblerInterface* masm) VIXL_OVERRIDE;
344
345 // Data address before it's moved into the code buffer.
346 const void* const addr_;
347 // When this flag is true, the label will be placed manually.
348 bool manually_placed_;
349 // When is the literal to be removed from the memory
350 // Can be delete'd when:
351 // moved into the code buffer: kDeletedOnPlacementByPool
352 // the pool is delete'd: kDeletedOnPoolDestruction
353 // or left to the application: kManuallyDeleted.
354 DeletionPolicy deletion_policy_;
355
356 friend class MacroAssembler;
357 };
358
359 template <typename T>
360 class Literal : public RawLiteral {
361 public:
362 explicit Literal(const T& value,
363 PlacementPolicy placement_policy = kPlacedWhenUsed,
364 DeletionPolicy deletion_policy = kManuallyDeleted)
365 : RawLiteral(&value_, sizeof(T), placement_policy, deletion_policy),
366 value_(value) {}
Literal(const T & value,DeletionPolicy deletion_policy)367 explicit Literal(const T& value, DeletionPolicy deletion_policy)
368 : RawLiteral(&value_, sizeof(T), deletion_policy), value_(value) {}
UpdateValue(const T & value,CodeBuffer * buffer)369 void UpdateValue(const T& value, CodeBuffer* buffer) {
370 value_ = value;
371 if (IsBound()) {
372 buffer->UpdateData(GetLocation(), GetDataAddress(), GetSize());
373 }
374 }
375
376 private:
377 T value_;
378 };
379
380 class StringLiteral : public RawLiteral {
381 public:
382 explicit StringLiteral(const char* str,
383 PlacementPolicy placement_policy = kPlacedWhenUsed,
384 DeletionPolicy deletion_policy = kManuallyDeleted)
385 : RawLiteral(str,
386 static_cast<int>(strlen(str) + 1),
387 placement_policy,
388 deletion_policy) {
389 VIXL_ASSERT((strlen(str) + 1) <= kMaxObjectSize);
390 }
StringLiteral(const char * str,DeletionPolicy deletion_policy)391 explicit StringLiteral(const char* str, DeletionPolicy deletion_policy)
392 : RawLiteral(str, static_cast<int>(strlen(str) + 1), deletion_policy) {
393 VIXL_ASSERT((strlen(str) + 1) <= kMaxObjectSize);
394 }
395 };
396
397 } // namespace aarch32
398
399
400 // Required InvalSet template specialisations.
401 #define INVAL_SET_TEMPLATE_PARAMETERS \
402 aarch32::Location::ForwardRef, aarch32::Location::kNPreallocatedElements, \
403 int32_t, aarch32::Location::kInvalidLinkKey, \
404 aarch32::Location::kReclaimFrom, aarch32::Location::kReclaimFactor
405 template <>
GetKey(const aarch32::Location::ForwardRef & element)406 inline int32_t InvalSet<INVAL_SET_TEMPLATE_PARAMETERS>::GetKey(
407 const aarch32::Location::ForwardRef& element) {
408 return element.GetLocation();
409 }
410 template <>
SetKey(aarch32::Location::ForwardRef * element,int32_t key)411 inline void InvalSet<INVAL_SET_TEMPLATE_PARAMETERS>::SetKey(
412 aarch32::Location::ForwardRef* element, int32_t key) {
413 element->SetLocationToInvalidateOnly(key);
414 }
415 #undef INVAL_SET_TEMPLATE_PARAMETERS
416
417 } // namespace vixl
418
419 #endif // VIXL_AARCH32_LABEL_AARCH32_H_
420