| // Copyright 2017, VIXL authors |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // * Redistributions of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // * Neither the name of ARM Limited nor the names of its contributors may be |
| // used to endorse or promote products derived from this software without |
| // specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND |
| // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE |
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #ifndef VIXL_AARCH32_LABEL_AARCH32_H_ |
| #define VIXL_AARCH32_LABEL_AARCH32_H_ |
| |
| extern "C" { |
| #include <stdint.h> |
| } |
| |
| #include <algorithm> |
| #include <cstddef> |
| #include <iomanip> |
| #include <list> |
| |
| #include "invalset-vixl.h" |
| #include "pool-manager.h" |
| #include "utils-vixl.h" |
| |
| #include "constants-aarch32.h" |
| #include "instructions-aarch32.h" |
| |
| namespace vixl { |
| |
| namespace aarch32 { |
| |
| class MacroAssembler; |
| |
| class Location : public LocationBase<int32_t> { |
| friend class Assembler; |
| friend class MacroAssembler; |
| |
| public: |
| // Unbound location that can be used with the assembler bind() method and |
| // with the assembler methods for generating instructions, but will never |
| // be handled by the pool manager. |
| Location() |
| : LocationBase<int32_t>(kRawLocation, 1 /* placeholder size*/), |
| referenced_(false) {} |
| |
| typedef int32_t Offset; |
| |
| ~Location() VIXL_NEGATIVE_TESTING_ALLOW_EXCEPTION { |
| #ifdef VIXL_DEBUG |
| if (IsReferenced() && !IsBound()) { |
| VIXL_ABORT_WITH_MSG("Location, label or literal used but not bound.\n"); |
| } |
| #endif |
| } |
| |
| Location(Location&&) = default; // movable |
| |
| bool IsReferenced() const { return referenced_; } |
| |
| private: |
| class EmitOperator { |
| public: |
| explicit EmitOperator(InstructionSet isa) : isa_(isa) { |
| #if defined(VIXL_INCLUDE_TARGET_A32_ONLY) |
| USE(isa_); |
| VIXL_ASSERT(isa == A32); |
| #elif defined(VIXL_INCLUDE_TARGET_T32_ONLY) |
| USE(isa_); |
| VIXL_ASSERT(isa == T32); |
| #endif |
| } |
| virtual ~EmitOperator() {} |
| virtual uint32_t Encode(uint32_t /*instr*/, |
| Location::Offset /*pc*/, |
| const Location* /*label*/) const { |
| return 0; |
| } |
| #if defined(VIXL_INCLUDE_TARGET_A32_ONLY) |
| bool IsUsingT32() const { return false; } |
| #elif defined(VIXL_INCLUDE_TARGET_T32_ONLY) |
| bool IsUsingT32() const { return true; } |
| #else |
| bool IsUsingT32() const { return isa_ == T32; } |
| #endif |
| |
| private: |
| InstructionSet isa_; |
| }; |
| |
| protected: |
| class ForwardRef : public ForwardReference<int32_t> { |
| public: |
| // Default constructor for InvalSet. |
| ForwardRef() : ForwardReference<int32_t>(0, 0, 0, 0, 1), op_(NULL) {} |
| |
| ForwardRef(const Location::EmitOperator* op, |
| int32_t location, |
| int size, |
| int32_t min_object_location, |
| int32_t max_object_location, |
| int object_alignment = 1) |
| : ForwardReference<int32_t>(location, |
| size, |
| min_object_location, |
| max_object_location, |
| object_alignment), |
| op_(op) {} |
| |
| const Location::EmitOperator* op() const { return op_; } |
| |
| // We must provide comparison operators to work with InvalSet. |
| bool operator==(const ForwardRef& other) const { |
| return GetLocation() == other.GetLocation(); |
| } |
| bool operator<(const ForwardRef& other) const { |
| return GetLocation() < other.GetLocation(); |
| } |
| bool operator<=(const ForwardRef& other) const { |
| return GetLocation() <= other.GetLocation(); |
| } |
| bool operator>(const ForwardRef& other) const { |
| return GetLocation() > other.GetLocation(); |
| } |
| |
| private: |
| const Location::EmitOperator* op_; |
| }; |
| |
| static const int kNPreallocatedElements = 4; |
| // The following parameters will not affect ForwardRefList in practice, as we |
| // resolve all references at once and clear the list, so we do not need to |
| // remove individual elements by invalidating them. |
| static const int32_t kInvalidLinkKey = INT32_MAX; |
| static const size_t kReclaimFrom = 512; |
| static const size_t kReclaimFactor = 2; |
| |
| typedef InvalSet<ForwardRef, |
| kNPreallocatedElements, |
| int32_t, |
| kInvalidLinkKey, |
| kReclaimFrom, |
| kReclaimFactor> |
| ForwardRefListBase; |
| typedef InvalSetIterator<ForwardRefListBase> ForwardRefListIteratorBase; |
| |
| class ForwardRefList : public ForwardRefListBase { |
| public: |
| ForwardRefList() : ForwardRefListBase() {} |
| |
| using ForwardRefListBase::Back; |
| using ForwardRefListBase::Front; |
| }; |
| |
| class ForwardRefListIterator : public ForwardRefListIteratorBase { |
| public: |
| explicit ForwardRefListIterator(Location* location) |
| : ForwardRefListIteratorBase(&location->forward_) {} |
| |
| // TODO: Remove these and use the STL-like interface instead. We'll need a |
| // const_iterator implemented for this. |
| using ForwardRefListIteratorBase::Advance; |
| using ForwardRefListIteratorBase::Current; |
| }; |
| |
| // For InvalSet::GetKey() and InvalSet::SetKey(). |
| friend class InvalSet<ForwardRef, |
| kNPreallocatedElements, |
| int32_t, |
| kInvalidLinkKey, |
| kReclaimFrom, |
| kReclaimFactor>; |
| |
| private: |
| virtual void ResolveReferences(internal::AssemblerBase* assembler) |
| VIXL_OVERRIDE; |
| |
| void SetReferenced() { referenced_ = true; } |
| |
| bool HasForwardReferences() const { return !forward_.empty(); } |
| |
| ForwardRef GetLastForwardReference() const { |
| VIXL_ASSERT(HasForwardReferences()); |
| return forward_.Back(); |
| } |
| |
| // Add forward reference to this object. Called from the assembler. |
| void AddForwardRef(int32_t instr_location, |
| const EmitOperator& op, |
| const ReferenceInfo* info); |
| |
| // Check if we need to add padding when binding this object, in order to |
| // meet the minimum location requirement. |
| bool Needs16BitPadding(int location) const; |
| |
| void EncodeLocationFor(internal::AssemblerBase* assembler, |
| int32_t from, |
| const Location::EmitOperator* encoder); |
| |
| // True if the label has been used at least once. |
| bool referenced_; |
| |
| protected: |
| // Types passed to LocationBase. Must be distinct for unbound Locations (not |
| // relevant for bound locations, as they don't have a corresponding |
| // PoolObject). |
| static const int kRawLocation = 0; // Will not be used by the pool manager. |
| static const int kVeneerType = 1; |
| static const int kLiteralType = 2; |
| |
| // Contains the references to the unbound label |
| ForwardRefList forward_; |
| |
| // To be used only by derived classes. |
| Location(uint32_t type, int size, int alignment) |
| : LocationBase<int32_t>(type, size, alignment), referenced_(false) {} |
| |
| // To be used only by derived classes. |
| explicit Location(Offset location) |
| : LocationBase<int32_t>(location), referenced_(false) {} |
| |
| virtual int GetMaxAlignment() const VIXL_OVERRIDE; |
| virtual int GetMinLocation() const VIXL_OVERRIDE; |
| |
| private: |
| // Included to make the class concrete, however should never be called. |
| virtual void EmitPoolObject(MacroAssemblerInterface* masm) VIXL_OVERRIDE { |
| USE(masm); |
| VIXL_UNREACHABLE(); |
| } |
| }; |
| |
| class Label : public Location { |
| static const int kVeneerSize = 4; |
| // Use an alignment of 1 for all architectures. Even though we can bind an |
| // unused label, because of the way the MacroAssembler works we can always be |
| // sure to have the correct buffer alignment for the instruction set we are |
| // using, so we do not need to enforce additional alignment requirements |
| // here. |
| // TODO: Consider modifying the interface of the pool manager to pass an |
| // optional additional alignment to Bind() in order to handle cases where the |
| // buffer could be unaligned. |
| static const int kVeneerAlignment = 1; |
| |
| public: |
| Label() : Location(kVeneerType, kVeneerSize, kVeneerAlignment) {} |
| explicit Label(Offset location) : Location(location) {} |
| |
| private: |
| virtual bool ShouldBeDeletedOnPlacementByPoolManager() const VIXL_OVERRIDE { |
| return false; |
| } |
| virtual bool ShouldDeletePoolObjectOnPlacement() const VIXL_OVERRIDE { |
| return false; |
| } |
| |
| virtual void UpdatePoolObject(PoolObject<int32_t>* object) VIXL_OVERRIDE; |
| virtual void EmitPoolObject(MacroAssemblerInterface* masm) VIXL_OVERRIDE; |
| |
| virtual bool UsePoolObjectEmissionMargin() const VIXL_OVERRIDE { |
| return true; |
| } |
| virtual int32_t GetPoolObjectEmissionMargin() const VIXL_OVERRIDE { |
| VIXL_ASSERT(UsePoolObjectEmissionMargin() == true); |
| return 1 * KBytes; |
| } |
| }; |
| |
| class RawLiteral : public Location { |
| // Some load instructions require alignment to 4 bytes. Since we do |
| // not know what instructions will reference a literal after we place |
| // it, we enforce a 4 byte alignment for literals that are 4 bytes or |
| // larger. |
| static const int kLiteralAlignment = 4; |
| |
| public: |
| enum PlacementPolicy { kPlacedWhenUsed, kManuallyPlaced }; |
| |
| enum DeletionPolicy { |
| kDeletedOnPlacementByPool, |
| kDeletedOnPoolDestruction, |
| kManuallyDeleted |
| }; |
| |
| RawLiteral(const void* addr, |
| int size, |
| PlacementPolicy placement_policy = kPlacedWhenUsed, |
| DeletionPolicy deletion_policy = kManuallyDeleted) |
| : Location(kLiteralType, |
| size, |
| (size < kLiteralAlignment) ? size : kLiteralAlignment), |
| addr_(addr), |
| manually_placed_(placement_policy == kManuallyPlaced), |
| deletion_policy_(deletion_policy) { |
| // We can't have manually placed literals that are not manually deleted. |
| VIXL_ASSERT(!IsManuallyPlaced() || |
| (GetDeletionPolicy() == kManuallyDeleted)); |
| } |
| RawLiteral(const void* addr, int size, DeletionPolicy deletion_policy) |
| : Location(kLiteralType, |
| size, |
| (size < kLiteralAlignment) ? size : kLiteralAlignment), |
| addr_(addr), |
| manually_placed_(false), |
| deletion_policy_(deletion_policy) {} |
| |
| // noncopyable to avoid one instruction appearing to refer to two or more literals |
| RawLiteral(const RawLiteral&) = delete; |
| |
| RawLiteral(RawLiteral &&) = default; // movable |
| |
| const void* GetDataAddress() const { return addr_; } |
| int GetSize() const { return GetPoolObjectSizeInBytes(); } |
| |
| bool IsManuallyPlaced() const { return manually_placed_; } |
| |
| private: |
| DeletionPolicy GetDeletionPolicy() const { return deletion_policy_; } |
| |
| virtual bool ShouldBeDeletedOnPlacementByPoolManager() const VIXL_OVERRIDE { |
| return GetDeletionPolicy() == kDeletedOnPlacementByPool; |
| } |
| virtual bool ShouldBeDeletedOnPoolManagerDestruction() const VIXL_OVERRIDE { |
| return GetDeletionPolicy() == kDeletedOnPoolDestruction; |
| } |
| virtual void EmitPoolObject(MacroAssemblerInterface* masm) VIXL_OVERRIDE; |
| |
| // Data address before it's moved into the code buffer. |
| const void* const addr_; |
| // When this flag is true, the label will be placed manually. |
| bool manually_placed_; |
| // When is the literal to be removed from the memory |
| // Can be delete'd when: |
| // moved into the code buffer: kDeletedOnPlacementByPool |
| // the pool is delete'd: kDeletedOnPoolDestruction |
| // or left to the application: kManuallyDeleted. |
| DeletionPolicy deletion_policy_; |
| |
| friend class MacroAssembler; |
| }; |
| |
| template <typename T> |
| class Literal : public RawLiteral { |
| public: |
| explicit Literal(const T& value, |
| PlacementPolicy placement_policy = kPlacedWhenUsed, |
| DeletionPolicy deletion_policy = kManuallyDeleted) |
| : RawLiteral(&value_, sizeof(T), placement_policy, deletion_policy), |
| value_(value) {} |
| explicit Literal(const T& value, DeletionPolicy deletion_policy) |
| : RawLiteral(&value_, sizeof(T), deletion_policy), value_(value) {} |
| void UpdateValue(const T& value, CodeBuffer* buffer) { |
| value_ = value; |
| if (IsBound()) { |
| buffer->UpdateData(GetLocation(), GetDataAddress(), GetSize()); |
| } |
| } |
| |
| private: |
| T value_; |
| }; |
| |
| class StringLiteral : public RawLiteral { |
| public: |
| explicit StringLiteral(const char* str, |
| PlacementPolicy placement_policy = kPlacedWhenUsed, |
| DeletionPolicy deletion_policy = kManuallyDeleted) |
| : RawLiteral(str, |
| static_cast<int>(strlen(str) + 1), |
| placement_policy, |
| deletion_policy) { |
| VIXL_ASSERT((strlen(str) + 1) <= kMaxObjectSize); |
| } |
| explicit StringLiteral(const char* str, DeletionPolicy deletion_policy) |
| : RawLiteral(str, static_cast<int>(strlen(str) + 1), deletion_policy) { |
| VIXL_ASSERT((strlen(str) + 1) <= kMaxObjectSize); |
| } |
| }; |
| |
| } // namespace aarch32 |
| |
| |
| // Required InvalSet template specialisations. |
| #define INVAL_SET_TEMPLATE_PARAMETERS \ |
| aarch32::Location::ForwardRef, aarch32::Location::kNPreallocatedElements, \ |
| int32_t, aarch32::Location::kInvalidLinkKey, \ |
| aarch32::Location::kReclaimFrom, aarch32::Location::kReclaimFactor |
| template <> |
| inline int32_t InvalSet<INVAL_SET_TEMPLATE_PARAMETERS>::GetKey( |
| const aarch32::Location::ForwardRef& element) { |
| return element.GetLocation(); |
| } |
| template <> |
| inline void InvalSet<INVAL_SET_TEMPLATE_PARAMETERS>::SetKey( |
| aarch32::Location::ForwardRef* element, int32_t key) { |
| element->SetLocationToInvalidateOnly(key); |
| } |
| #undef INVAL_SET_TEMPLATE_PARAMETERS |
| |
| } // namespace vixl |
| |
| #endif // VIXL_AARCH32_LABEL_AARCH32_H_ |