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.amd64; 24 25 import static jdk.vm.ci.amd64.AMD64.*; 26 27 import java.util.*; 28 29 import jdk.vm.ci.amd64.*; 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 AMD64HotSpotRegisterConfig 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; 80 private final Register[] nativeGeneralParameterRegisters; 81 private final Register[] xmmParameterRegisters = {xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7}; 82 83 /* 84 * Some ABIs (e.g. Windows) require a so-called "home space", that is a save area on the stack 85 * to store the argument registers 86 */ 87 private final boolean needsNativeStackHomeSpace; 88 89 private static Register[] initAllocatable(boolean reserveForHeapBase) { 90 Register[] registers = null; 91 // @formatter:off 92 if (reserveForHeapBase) { 93 registers = new Register[] { 94 rax, rbx, rcx, rdx, /*rsp,*/ rbp, rsi, rdi, r8, r9, r10, r11, /*r12,*/ r13, r14, /*r15, */ 95 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 96 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 97 }; 98 } else { 99 registers = new Register[] { 100 rax, rbx, rcx, rdx, /*rsp,*/ rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, /*r15, */ 101 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 102 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 103 }; 104 } 105 // @formatter:on 106 return registers; 107 } 108 109 public AMD64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config) { 110 this(architecture, config, initAllocatable(config.useCompressedOops)); 111 assert callerSaved.length >= allocatable.length; 112 } 113 114 public AMD64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config, Register[] allocatable) { 115 this.architecture = architecture; 116 this.maxFrameSize = config.maxFrameSize; 117 118 if (config.windowsOs) { 119 javaGeneralParameterRegisters = new Register[]{rdx, r8, r9, rdi, rsi, rcx}; 120 nativeGeneralParameterRegisters = new Register[]{rcx, rdx, r8, r9}; 121 this.needsNativeStackHomeSpace = true; 122 } else { 123 javaGeneralParameterRegisters = new Register[]{rsi, rdx, rcx, r8, r9, rdi}; 124 nativeGeneralParameterRegisters = new Register[]{rdi, rsi, rdx, rcx, r8, r9}; 125 this.needsNativeStackHomeSpace = false; 126 } 127 128 this.allocatable = allocatable.clone(); 129 Set<Register> callerSaveSet = new HashSet<>(); 130 Collections.addAll(callerSaveSet, allocatable); 131 Collections.addAll(callerSaveSet, xmmParameterRegisters); 132 Collections.addAll(callerSaveSet, javaGeneralParameterRegisters); 133 Collections.addAll(callerSaveSet, nativeGeneralParameterRegisters); 134 callerSaved = callerSaveSet.toArray(new Register[callerSaveSet.size()]); 135 136 allAllocatableAreCallerSaved = true; 137 attributesMap = RegisterAttributes.createMap(this, AMD64.allRegisters); 138 } 139 140 @Override 141 public Register[] getCallerSaveRegisters() { 142 return callerSaved; 143 } 144 145 public Register[] getCalleeSaveRegisters() { 146 return null; 147 } 148 149 @Override 150 public boolean areAllAllocatableRegistersCallerSaved() { 151 return allAllocatableAreCallerSaved; 152 } 153 154 @Override 155 public Register getRegisterForRole(int index) { 156 throw new UnsupportedOperationException(); 157 } 158 159 @Override 160 public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target, boolean stackOnly) { 161 if (type == Type.NativeCall) { 162 return callingConvention(nativeGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly); 163 } 164 // On x64, parameter locations are the same whether viewed 165 // from the caller or callee perspective 166 return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly); 167 } 168 169 public Register[] getCallingConventionRegisters(Type type, JavaKind kind) { 170 switch (kind) { 171 case Boolean: 172 case Byte: 173 case Short: 174 case Char: 175 case Int: 176 case Long: 177 case Object: 178 return type == Type.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters; 179 case Float: 180 case Double: 181 return xmmParameterRegisters; 182 default: 183 throw JVMCIError.shouldNotReachHere(); 184 } 185 } 186 187 private CallingConvention callingConvention(Register[] generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, Type type, TargetDescription target, boolean stackOnly) { 188 AllocatableValue[] locations = new AllocatableValue[parameterTypes.length]; 189 190 int currentGeneral = 0; 191 int currentXMM = 0; 192 int currentStackOffset = type == Type.NativeCall && needsNativeStackHomeSpace ? generalParameterRegisters.length * target.wordSize : 0; 193 194 for (int i = 0; i < parameterTypes.length; i++) { 195 final JavaKind kind = parameterTypes[i].getJavaKind().getStackKind(); 196 197 switch (kind) { 198 case Byte: 199 case Boolean: 200 case Short: 201 case Char: 202 case Int: 203 case Long: 204 case Object: 205 if (!stackOnly && currentGeneral < generalParameterRegisters.length) { 206 Register register = generalParameterRegisters[currentGeneral++]; 207 locations[i] = register.asValue(target.getLIRKind(kind)); 208 } 209 break; 210 case Float: 211 case Double: 212 if (!stackOnly && currentXMM < xmmParameterRegisters.length) { 213 Register register = xmmParameterRegisters[currentXMM++]; 214 locations[i] = register.asValue(target.getLIRKind(kind)); 215 } 216 break; 217 default: 218 throw JVMCIError.shouldNotReachHere(); 219 } 220 221 if (locations[i] == null) { 222 LIRKind lirKind = target.getLIRKind(kind); 223 locations[i] = StackSlot.get(lirKind, currentStackOffset, !type.out); 224 currentStackOffset += Math.max(target.getSizeInBytes(lirKind.getPlatformKind()), target.wordSize); 225 } 226 } 227 228 JavaKind returnKind = returnType == null ? JavaKind.Void : returnType.getJavaKind(); 229 AllocatableValue returnLocation = returnKind == JavaKind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(target.getLIRKind(returnKind.getStackKind())); 230 return new CallingConvention(currentStackOffset, returnLocation, locations); 231 } 232 233 @Override 234 public Register getReturnRegister(JavaKind kind) { 235 switch (kind) { 236 case Boolean: 237 case Byte: 238 case Char: 239 case Short: 240 case Int: 241 case Long: 242 case Object: 243 return rax; 244 case Float: 245 case Double: 246 return xmm0; 247 case Void: 248 case Illegal: 249 return null; 250 default: 251 throw new UnsupportedOperationException("no return register for type " + kind); 252 } 253 } 254 255 @Override 256 public Register getFrameRegister() { 257 return rsp; 258 } 259 260 @Override 261 public String toString() { 262 return String.format("Allocatable: " + Arrays.toString(getAllocatableRegisters()) + "%n" + "CallerSave: " + Arrays.toString(getCallerSaveRegisters()) + "%n"); 263 } 264 }