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 }