Home | History | Annotate | Download | only in aarch64
      1 // Copyright 2016, 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 // The ABI features are only supported with C++11 or later.
     28 #if __cplusplus >= 201103L
     29 // This should not be defined manually.
     30 #define VIXL_HAS_ABI_SUPPORT
     31 #elif defined(VIXL_HAS_ABI_SUPPORT)
     32 #error "The ABI support requires C++11 or later."
     33 #endif
     34 
     35 #ifdef VIXL_HAS_ABI_SUPPORT
     36 
     37 #ifndef VIXL_AARCH64_ABI_AARCH64_H_
     38 #define VIXL_AARCH64_ABI_AARCH64_H_
     39 
     40 #include <algorithm>
     41 #include <type_traits>
     42 
     43 #include "../globals-vixl.h"
     44 
     45 #include "instructions-aarch64.h"
     46 #include "operands-aarch64.h"
     47 
     48 namespace vixl {
     49 namespace aarch64 {
     50 
     51 // Class describing the AArch64 procedure call standard, as defined in "ARM
     52 // Procedure Call Standard for the ARM 64-bit Architecture (AArch64)",
     53 // release 1.0 (AAPCS below).
     54 //
     55 // The stages in the comments match the description in that document.
     56 //
     57 // Stage B does not apply to arguments handled by this class.
     58 class ABI {
     59  public:
     60   explicit ABI(Register stack_pointer = sp) : stack_pointer_(stack_pointer) {
     61     // Stage A - Initialization
     62     Reset();
     63   }
     64 
     65   void Reset() {
     66     NGRN_ = 0;
     67     NSRN_ = 0;
     68     stack_offset_ = 0;
     69   }
     70 
     71   int GetStackSpaceRequired() { return stack_offset_; }
     72 
     73   // The logic is described in section 5.5 of the AAPCS.
     74   template <typename T>
     75   GenericOperand GetReturnGenericOperand() const {
     76     ABI abi(stack_pointer_);
     77     GenericOperand result = abi.GetNextParameterGenericOperand<T>();
     78     VIXL_ASSERT(result.IsCPURegister());
     79     return result;
     80   }
     81 
     82   // The logic is described in section 5.4.2 of the AAPCS.
     83   // The `GenericOperand` returned describes the location reserved for the
     84   // argument from the point of view of the callee.
     85   template <typename T>
     86   GenericOperand GetNextParameterGenericOperand() {
     87     const bool is_floating_point_type = std::is_floating_point<T>::value;
     88     const bool is_integral_type =
     89         std::is_integral<T>::value || std::is_enum<T>::value;
     90     const bool is_pointer_type = std::is_pointer<T>::value;
     91     int type_alignment = std::alignment_of<T>::value;
     92 
     93     // We only support basic types.
     94     VIXL_ASSERT(is_floating_point_type || is_integral_type || is_pointer_type);
     95 
     96     // To ensure we get the correct type of operand when simulating on a 32-bit
     97     // host, force the size of pointer types to the native AArch64 pointer size.
     98     unsigned size = is_pointer_type ? 8 : sizeof(T);
     99     // The size of the 'operand' reserved for the argument.
    100     unsigned operand_size = AlignUp(size, kWRegSizeInBytes);
    101     if (size > 8) {
    102       VIXL_UNIMPLEMENTED();
    103       return GenericOperand();
    104     }
    105 
    106     // Stage C.1
    107     if (is_floating_point_type && (NSRN_ < 8)) {
    108       return GenericOperand(FPRegister(NSRN_++, size * kBitsPerByte));
    109     }
    110     // Stages C.2, C.3, and C.4: Unsupported. Caught by the assertions above.
    111     // Stages C.5 and C.6
    112     if (is_floating_point_type) {
    113       VIXL_STATIC_ASSERT(
    114           !is_floating_point_type ||
    115           (std::is_same<T, float>::value || std::is_same<T, double>::value));
    116       int offset = stack_offset_;
    117       stack_offset_ += 8;
    118       return GenericOperand(MemOperand(stack_pointer_, offset), operand_size);
    119     }
    120     // Stage C.7
    121     if ((is_integral_type || is_pointer_type) && (size <= 8) && (NGRN_ < 8)) {
    122       return GenericOperand(Register(NGRN_++, operand_size * kBitsPerByte));
    123     }
    124     // Stage C.8
    125     if (type_alignment == 16) {
    126       NGRN_ = AlignUp(NGRN_, 2);
    127     }
    128     // Stage C.9
    129     if (is_integral_type && (size == 16) && (NGRN_ < 7)) {
    130       VIXL_UNIMPLEMENTED();
    131       return GenericOperand();
    132     }
    133     // Stage C.10: Unsupported. Caught by the assertions above.
    134     // Stage C.11
    135     NGRN_ = 8;
    136     // Stage C.12
    137     stack_offset_ = AlignUp(stack_offset_, std::max(type_alignment, 8));
    138     // Stage C.13: Unsupported. Caught by the assertions above.
    139     // Stage C.14
    140     VIXL_ASSERT(size <= 8u);
    141     size = std::max(size, 8u);
    142     int offset = stack_offset_;
    143     stack_offset_ += size;
    144     return GenericOperand(MemOperand(stack_pointer_, offset), operand_size);
    145   }
    146 
    147  private:
    148   Register stack_pointer_;
    149   // Next General-purpose Register Number.
    150   int NGRN_;
    151   // Next SIMD and Floating-point Register Number.
    152   int NSRN_;
    153   // The acronym "NSAA" used in the standard refers to the "Next Stacked
    154   // Argument Address". Here we deal with offsets from the stack pointer.
    155   int stack_offset_;
    156 };
    157 
    158 template <>
    159 inline GenericOperand ABI::GetReturnGenericOperand<void>() const {
    160   return GenericOperand();
    161 }
    162 }
    163 }  // namespace vixl::aarch64
    164 
    165 #endif  // VIXL_AARCH64_ABI_AARCH64_H_
    166 
    167 #endif  // VIXL_HAS_ABI_SUPPORT
    168