1 /*
   2  * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package jdk.vm.ci.hotspot.aarch64;
  24 
  25 import static jdk.vm.ci.aarch64.AArch64.*;
  26 
  27 import java.util.*;
  28 
  29 import jdk.vm.ci.aarch64.*;
  30 import jdk.vm.ci.code.*;
  31 import jdk.vm.ci.code.CallingConvention.*;
  32 import jdk.vm.ci.common.*;
  33 import jdk.vm.ci.hotspot.*;
  34 import jdk.vm.ci.meta.*;
  35 
  36 public class AArch64HotSpotRegisterConfig implements RegisterConfig {
  37 
  38     private final Architecture architecture;
  39 
  40     private final Register[] allocatable;
  41 
  42     private final int maxFrameSize;
  43 
  44     /**
  45      * The caller saved registers always include all parameter registers.
  46      */
  47     private final Register[] callerSaved;
  48 
  49     private final boolean allAllocatableAreCallerSaved;
  50 
  51     private final RegisterAttributes[] attributesMap;
  52 
  53     public int getMaximumFrameSize() {
  54         return maxFrameSize;
  55     }
  56 
  57     @Override
  58     public Register[] getAllocatableRegisters() {
  59         return allocatable.clone();
  60     }
  61 
  62     public Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers) {
  63         ArrayList<Register> list = new ArrayList<>();
  64         for (Register reg : registers) {
  65             if (architecture.canStoreValue(reg.getRegisterCategory(), kind)) {
  66                 list.add(reg);
  67             }
  68         }
  69 
  70         Register[] ret = list.toArray(new Register[list.size()]);
  71         return ret;
  72     }
  73 
  74     @Override
  75     public RegisterAttributes[] getAttributesMap() {
  76         return attributesMap.clone();
  77     }
  78 
  79     private final Register[] javaGeneralParameterRegisters = {r1, r2, r3, r4, r5, r6, r7, r0};
  80     private final Register[] nativeGeneralParameterRegisters = {r0, r1, r2, r3, r4, r5, r6, r7};
  81     private final Register[] simdParameterRegisters = {v0, v1, v2, v3, v4, v5, v6, v7};
  82 
  83     /*
  84      * Some ABIs (e.g. Windows) require a so-called "home space", that
  85      * is a save area on the stack to store the argument registers
  86      */
  87     private final boolean needsNativeStackHomeSpace = false;
  88 
  89     private static Register[] initAllocatable(boolean reserveForHeapBase) {
  90         Register[] registers = new Register[] {
  91             r0, r1, r2, r3, r4, r5, r6, r7, r8, r9,
  92             r10, r11, r12, r13, r14, r15, r16, r17, r18, r19,
  93             r20, r21, r22, r23, r24, r25, r26, r27,
  94             rheapbase, rthread, fp, lr, sp,
  95             v0, v1, v2, v3, v4, v5, v6, v7, v8, v9,
  96             v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
  97             v20, v21, v22, v23, v24, v25, v26
  98         };
  99         return registers;
 100     }
 101 
 102     public AArch64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config) {
 103         this(architecture, config, initAllocatable(config.useCompressedOops));
 104         assert callerSaved.length >= allocatable.length;
 105     }
 106 
 107     public AArch64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config, Register[] allocatable) {
 108         this.architecture = architecture;
 109         this.maxFrameSize = config.maxFrameSize;
 110 
 111         this.allocatable = allocatable.clone();
 112         Set<Register> callerSaveSet = new HashSet<>();
 113         Collections.addAll(callerSaveSet, allocatable);
 114         Collections.addAll(callerSaveSet, simdParameterRegisters);
 115         Collections.addAll(callerSaveSet, javaGeneralParameterRegisters);
 116         Collections.addAll(callerSaveSet, nativeGeneralParameterRegisters);
 117         callerSaved = callerSaveSet.toArray(new Register[callerSaveSet.size()]);
 118 
 119         allAllocatableAreCallerSaved = true;
 120         attributesMap = RegisterAttributes.createMap(this, AArch64.allRegisters);
 121     }
 122 
 123     @Override
 124     public Register[] getCallerSaveRegisters() {
 125         return callerSaved;
 126     }
 127 
 128     public Register[] getCalleeSaveRegisters() {
 129         return null;
 130     }
 131 
 132     @Override
 133     public boolean areAllAllocatableRegistersCallerSaved() {
 134         return allAllocatableAreCallerSaved;
 135     }
 136 
 137     @Override
 138     public Register getRegisterForRole(int index) {
 139         throw new UnsupportedOperationException();
 140     }
 141 
 142     @Override
 143     public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target, boolean stackOnly) {
 144         if (type == Type.NativeCall) {
 145             return callingConvention(nativeGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly);
 146         }
 147         // On x64, parameter locations are the same whether viewed
 148         // from the caller or callee perspective
 149         return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly);
 150     }
 151 
 152     public Register[] getCallingConventionRegisters(Type type, JavaKind kind) {
 153         switch (kind) {
 154             case Boolean:
 155             case Byte:
 156             case Short:
 157             case Char:
 158             case Int:
 159             case Long:
 160             case Object:
 161                 return type == Type.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters;
 162             case Float:
 163             case Double:
 164                 return simdParameterRegisters;
 165             default:
 166                 throw JVMCIError.shouldNotReachHere();
 167         }
 168     }
 169 
 170     private CallingConvention callingConvention(Register[] generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, Type type, TargetDescription target, boolean stackOnly) {
 171         AllocatableValue[] locations = new AllocatableValue[parameterTypes.length];
 172 
 173         int currentGeneral = 0;
 174         int currentSIMD = 0;
 175         int currentStackOffset = type == Type.NativeCall && needsNativeStackHomeSpace ? generalParameterRegisters.length * target.wordSize : 0;
 176 
 177         for (int i = 0; i < parameterTypes.length; i++) {
 178             final JavaKind kind = parameterTypes[i].getJavaKind().getStackKind();
 179 
 180             switch (kind) {
 181                 case Byte:
 182                 case Boolean:
 183                 case Short:
 184                 case Char:
 185                 case Int:
 186                 case Long:
 187                 case Object:
 188                     if (!stackOnly && currentGeneral < generalParameterRegisters.length) {
 189                         Register register = generalParameterRegisters[currentGeneral++];
 190                         locations[i] = register.asValue(target.getLIRKind(kind));
 191                     }
 192                     break;
 193                 case Float:
 194                 case Double:
 195                     if (!stackOnly && currentSIMD < simdParameterRegisters.length) {
 196                         Register register = simdParameterRegisters[currentSIMD++];
 197                         locations[i] = register.asValue(target.getLIRKind(kind));
 198                     }
 199                     break;
 200                 default:
 201                     throw JVMCIError.shouldNotReachHere();
 202             }
 203 
 204             if (locations[i] == null) {
 205                 LIRKind lirKind = target.getLIRKind(kind);
 206                 locations[i] = StackSlot.get(lirKind, currentStackOffset, !type.out);
 207                 currentStackOffset += Math.max(target.getSizeInBytes(lirKind.getPlatformKind()), target.wordSize);
 208             }
 209         }
 210 
 211         JavaKind returnKind = returnType == null ? JavaKind.Void : returnType.getJavaKind();
 212         AllocatableValue returnLocation = returnKind == JavaKind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(target.getLIRKind(returnKind.getStackKind()));
 213         return new CallingConvention(currentStackOffset, returnLocation, locations);
 214     }
 215 
 216     @Override
 217     public Register getReturnRegister(JavaKind kind) {
 218         switch (kind) {
 219             case Boolean:
 220             case Byte:
 221             case Char:
 222             case Short:
 223             case Int:
 224             case Long:
 225             case Object:
 226                 return r0;
 227             case Float:
 228             case Double:
 229                 return v0;
 230             case Void:
 231             case Illegal:
 232                 return null;
 233             default:
 234                 throw new UnsupportedOperationException("no return register for type " + kind);
 235         }
 236     }
 237 
 238     @Override
 239     public Register getFrameRegister() {
 240         return sp;
 241     }
 242 
 243     @Override
 244     public String toString() {
 245         return String.format("Allocatable: " + Arrays.toString(getAllocatableRegisters()) + "%n" + "CallerSave:  " + Arrays.toString(getCallerSaveRegisters()) + "%n");
 246     }
 247 }