Home | History | Annotate | Download | only in mips64
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "calling_convention_mips64.h"
     18 
     19 #include <android-base/logging.h>
     20 
     21 #include "arch/instruction_set.h"
     22 #include "handle_scope-inl.h"
     23 #include "utils/mips64/managed_register_mips64.h"
     24 
     25 namespace art {
     26 namespace mips64 {
     27 
     28 // Up to kow many args can be enregistered. The rest of the args must go on the stack.
     29 constexpr size_t kMaxRegisterArguments = 8u;
     30 
     31 static const GpuRegister kGpuArgumentRegisters[] = {
     32   A0, A1, A2, A3, A4, A5, A6, A7
     33 };
     34 
     35 static const FpuRegister kFpuArgumentRegisters[] = {
     36   F12, F13, F14, F15, F16, F17, F18, F19
     37 };
     38 
     39 static constexpr ManagedRegister kCalleeSaveRegisters[] = {
     40     // Core registers.
     41     Mips64ManagedRegister::FromGpuRegister(S2),
     42     Mips64ManagedRegister::FromGpuRegister(S3),
     43     Mips64ManagedRegister::FromGpuRegister(S4),
     44     Mips64ManagedRegister::FromGpuRegister(S5),
     45     Mips64ManagedRegister::FromGpuRegister(S6),
     46     Mips64ManagedRegister::FromGpuRegister(S7),
     47     Mips64ManagedRegister::FromGpuRegister(GP),
     48     Mips64ManagedRegister::FromGpuRegister(S8),
     49     // No hard float callee saves.
     50 };
     51 
     52 static constexpr uint32_t CalculateCoreCalleeSpillMask() {
     53   // RA is a special callee save which is not reported by CalleeSaveRegisters().
     54   uint32_t result = 1 << RA;
     55   for (auto&& r : kCalleeSaveRegisters) {
     56     if (r.AsMips64().IsGpuRegister()) {
     57       result |= (1 << r.AsMips64().AsGpuRegister());
     58     }
     59   }
     60   return result;
     61 }
     62 
     63 static constexpr uint32_t kCoreCalleeSpillMask = CalculateCoreCalleeSpillMask();
     64 static constexpr uint32_t kFpCalleeSpillMask = 0u;
     65 
     66 // Calling convention
     67 ManagedRegister Mips64ManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
     68   return Mips64ManagedRegister::FromGpuRegister(T9);
     69 }
     70 
     71 ManagedRegister Mips64JniCallingConvention::InterproceduralScratchRegister() {
     72   return Mips64ManagedRegister::FromGpuRegister(T9);
     73 }
     74 
     75 static ManagedRegister ReturnRegisterForShorty(const char* shorty) {
     76   if (shorty[0] == 'F' || shorty[0] == 'D') {
     77     return Mips64ManagedRegister::FromFpuRegister(F0);
     78   } else if (shorty[0] == 'V') {
     79     return Mips64ManagedRegister::NoRegister();
     80   } else {
     81     return Mips64ManagedRegister::FromGpuRegister(V0);
     82   }
     83 }
     84 
     85 ManagedRegister Mips64ManagedRuntimeCallingConvention::ReturnRegister() {
     86   return ReturnRegisterForShorty(GetShorty());
     87 }
     88 
     89 ManagedRegister Mips64JniCallingConvention::ReturnRegister() {
     90   return ReturnRegisterForShorty(GetShorty());
     91 }
     92 
     93 ManagedRegister Mips64JniCallingConvention::IntReturnRegister() {
     94   return Mips64ManagedRegister::FromGpuRegister(V0);
     95 }
     96 
     97 // Managed runtime calling convention
     98 
     99 ManagedRegister Mips64ManagedRuntimeCallingConvention::MethodRegister() {
    100   return Mips64ManagedRegister::FromGpuRegister(A0);
    101 }
    102 
    103 bool Mips64ManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
    104   return false;  // Everything moved to stack on entry.
    105 }
    106 
    107 bool Mips64ManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
    108   return true;
    109 }
    110 
    111 ManagedRegister Mips64ManagedRuntimeCallingConvention::CurrentParamRegister() {
    112   LOG(FATAL) << "Should not reach here";
    113   UNREACHABLE();
    114 }
    115 
    116 FrameOffset Mips64ManagedRuntimeCallingConvention::CurrentParamStackOffset() {
    117   CHECK(IsCurrentParamOnStack());
    118   FrameOffset result =
    119       FrameOffset(displacement_.Int32Value() +  // displacement
    120                   kFramePointerSize +  // Method ref
    121                   (itr_slots_ * sizeof(uint32_t)));  // offset into in args
    122   return result;
    123 }
    124 
    125 const ManagedRegisterEntrySpills& Mips64ManagedRuntimeCallingConvention::EntrySpills() {
    126   // We spill the argument registers on MIPS64 to free them up for scratch use,
    127   // we then assume all arguments are on the stack.
    128   if ((entry_spills_.size() == 0) && (NumArgs() > 0)) {
    129     int reg_index = 1;   // we start from A1, A0 holds ArtMethod*.
    130 
    131     // We need to choose the correct register size since the managed
    132     // stack uses 32bit stack slots.
    133     ResetIterator(FrameOffset(0));
    134     while (HasNext()) {
    135       if (reg_index < 8) {
    136         if (IsCurrentParamAFloatOrDouble()) {  // FP regs.
    137           FpuRegister arg = kFpuArgumentRegisters[reg_index];
    138           Mips64ManagedRegister reg = Mips64ManagedRegister::FromFpuRegister(arg);
    139           entry_spills_.push_back(reg, IsCurrentParamADouble() ? 8 : 4);
    140         } else {  // GP regs.
    141           GpuRegister arg = kGpuArgumentRegisters[reg_index];
    142           Mips64ManagedRegister reg = Mips64ManagedRegister::FromGpuRegister(arg);
    143           entry_spills_.push_back(reg,
    144                                   (IsCurrentParamALong() && (!IsCurrentParamAReference())) ? 8 : 4);
    145         }
    146         // e.g. A1, A2, F3, A4, F5, F6, A7
    147         reg_index++;
    148       }
    149 
    150       Next();
    151     }
    152   }
    153   return entry_spills_;
    154 }
    155 
    156 // JNI calling convention
    157 
    158 Mips64JniCallingConvention::Mips64JniCallingConvention(bool is_static,
    159                                                        bool is_synchronized,
    160                                                        bool is_critical_native,
    161                                                        const char* shorty)
    162     : JniCallingConvention(is_static,
    163                            is_synchronized,
    164                            is_critical_native,
    165                            shorty,
    166                            kMips64PointerSize) {
    167 }
    168 
    169 uint32_t Mips64JniCallingConvention::CoreSpillMask() const {
    170   return kCoreCalleeSpillMask;
    171 }
    172 
    173 uint32_t Mips64JniCallingConvention::FpSpillMask() const {
    174   return kFpCalleeSpillMask;
    175 }
    176 
    177 ManagedRegister Mips64JniCallingConvention::ReturnScratchRegister() const {
    178   return Mips64ManagedRegister::FromGpuRegister(AT);
    179 }
    180 
    181 size_t Mips64JniCallingConvention::FrameSize() {
    182   // ArtMethod*, RA and callee save area size, local reference segment state.
    183   size_t method_ptr_size = static_cast<size_t>(kFramePointerSize);
    184   size_t ra_and_callee_save_area_size = (CalleeSaveRegisters().size() + 1) * kFramePointerSize;
    185 
    186   size_t frame_data_size = method_ptr_size + ra_and_callee_save_area_size;
    187   if (LIKELY(HasLocalReferenceSegmentState())) {                     // Local ref. segment state.
    188     // Local reference segment state is sometimes excluded.
    189     frame_data_size += sizeof(uint32_t);
    190   }
    191   // References plus 2 words for HandleScope header.
    192   size_t handle_scope_size = HandleScope::SizeOf(kMips64PointerSize, ReferenceCount());
    193 
    194   size_t total_size = frame_data_size;
    195   if (LIKELY(HasHandleScope())) {
    196     // HandleScope is sometimes excluded.
    197     total_size += handle_scope_size;                                 // Handle scope size.
    198   }
    199 
    200   // Plus return value spill area size.
    201   total_size += SizeOfReturnValue();
    202 
    203   return RoundUp(total_size, kStackAlignment);
    204 }
    205 
    206 size_t Mips64JniCallingConvention::OutArgSize() {
    207   return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize, kStackAlignment);
    208 }
    209 
    210 ArrayRef<const ManagedRegister> Mips64JniCallingConvention::CalleeSaveRegisters() const {
    211   return ArrayRef<const ManagedRegister>(kCalleeSaveRegisters);
    212 }
    213 
    214 bool Mips64JniCallingConvention::IsCurrentParamInRegister() {
    215   return itr_args_ < kMaxRegisterArguments;
    216 }
    217 
    218 bool Mips64JniCallingConvention::IsCurrentParamOnStack() {
    219   return !IsCurrentParamInRegister();
    220 }
    221 
    222 ManagedRegister Mips64JniCallingConvention::CurrentParamRegister() {
    223   CHECK(IsCurrentParamInRegister());
    224   if (IsCurrentParamAFloatOrDouble()) {
    225     return Mips64ManagedRegister::FromFpuRegister(kFpuArgumentRegisters[itr_args_]);
    226   } else {
    227     return Mips64ManagedRegister::FromGpuRegister(kGpuArgumentRegisters[itr_args_]);
    228   }
    229 }
    230 
    231 FrameOffset Mips64JniCallingConvention::CurrentParamStackOffset() {
    232   CHECK(IsCurrentParamOnStack());
    233   size_t args_on_stack = itr_args_ - kMaxRegisterArguments;
    234   size_t offset = displacement_.Int32Value() - OutArgSize() + (args_on_stack * kFramePointerSize);
    235   CHECK_LT(offset, OutArgSize());
    236   return FrameOffset(offset);
    237 }
    238 
    239 size_t Mips64JniCallingConvention::NumberOfOutgoingStackArgs() {
    240   // all arguments including JNI args
    241   size_t all_args = NumArgs() + NumberOfExtraArgumentsForJni();
    242 
    243   // Nothing on the stack unless there are more than 8 arguments
    244   return (all_args > kMaxRegisterArguments) ? all_args - kMaxRegisterArguments : 0;
    245 }
    246 }  // namespace mips64
    247 }  // namespace art
    248