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