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