001/* 002 * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package jdk.internal.jvmci.hotspot.amd64; 024 025import static jdk.internal.jvmci.amd64.AMD64.*; 026 027import java.util.*; 028 029import jdk.internal.jvmci.amd64.*; 030import jdk.internal.jvmci.code.*; 031import jdk.internal.jvmci.code.CallingConvention.*; 032import jdk.internal.jvmci.common.*; 033import jdk.internal.jvmci.hotspot.*; 034import jdk.internal.jvmci.meta.*; 035 036public class AMD64HotSpotRegisterConfig implements RegisterConfig { 037 038 private final Architecture architecture; 039 040 private final Register[] allocatable; 041 042 private final int maxFrameSize; 043 044 /** 045 * The caller saved registers always include all parameter registers. 046 */ 047 private final Register[] callerSaved; 048 049 private final boolean allAllocatableAreCallerSaved; 050 051 private final RegisterAttributes[] attributesMap; 052 053 public int getMaximumFrameSize() { 054 return maxFrameSize; 055 } 056 057 @Override 058 public Register[] getAllocatableRegisters() { 059 return allocatable.clone(); 060 } 061 062 public Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers) { 063 ArrayList<Register> list = new ArrayList<>(); 064 for (Register reg : registers) { 065 if (architecture.canStoreValue(reg.getRegisterCategory(), kind)) { 066 list.add(reg); 067 } 068 } 069 070 Register[] ret = list.toArray(new Register[list.size()]); 071 return ret; 072 } 073 074 @Override 075 public RegisterAttributes[] getAttributesMap() { 076 return attributesMap.clone(); 077 } 078 079 private final Register[] javaGeneralParameterRegisters; 080 private final Register[] nativeGeneralParameterRegisters; 081 private final Register[] xmmParameterRegisters = {xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7}; 082 083 /* 084 * Some ABIs (e.g. Windows) require a so-called "home space", that is a save area on the stack 085 * to store the argument registers 086 */ 087 private final boolean needsNativeStackHomeSpace; 088 089 private final CalleeSaveLayout csl; 090 091 private static Register[] initAllocatable(boolean reserveForHeapBase) { 092 Register[] registers = null; 093 // @formatter:off 094 if (reserveForHeapBase) { 095 registers = new Register[] { 096 rax, rbx, rcx, rdx, /*rsp,*/ rbp, rsi, rdi, r8, r9, r10, r11, /*r12,*/ r13, r14, /*r15, */ 097 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 098 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 099 }; 100 } else { 101 registers = new Register[] { 102 rax, rbx, rcx, rdx, /*rsp,*/ rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, /*r15, */ 103 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 104 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 105 }; 106 } 107 // @formatter:on 108 return registers; 109 } 110 111 public AMD64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config) { 112 this(architecture, config, initAllocatable(config.useCompressedOops)); 113 assert callerSaved.length >= allocatable.length; 114 } 115 116 public AMD64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config, Register[] allocatable) { 117 this.architecture = architecture; 118 this.maxFrameSize = config.maxFrameSize; 119 120 if (config.windowsOs) { 121 javaGeneralParameterRegisters = new Register[]{rdx, r8, r9, rdi, rsi, rcx}; 122 nativeGeneralParameterRegisters = new Register[]{rcx, rdx, r8, r9}; 123 this.needsNativeStackHomeSpace = true; 124 } else { 125 javaGeneralParameterRegisters = new Register[]{rsi, rdx, rcx, r8, r9, rdi}; 126 nativeGeneralParameterRegisters = new Register[]{rdi, rsi, rdx, rcx, r8, r9}; 127 this.needsNativeStackHomeSpace = false; 128 } 129 130 csl = null; 131 this.allocatable = allocatable.clone(); 132 Set<Register> callerSaveSet = new HashSet<>(); 133 Collections.addAll(callerSaveSet, allocatable); 134 Collections.addAll(callerSaveSet, xmmParameterRegisters); 135 Collections.addAll(callerSaveSet, javaGeneralParameterRegisters); 136 Collections.addAll(callerSaveSet, nativeGeneralParameterRegisters); 137 callerSaved = callerSaveSet.toArray(new Register[callerSaveSet.size()]); 138 139 allAllocatableAreCallerSaved = true; 140 attributesMap = RegisterAttributes.createMap(this, AMD64.allRegisters); 141 } 142 143 @Override 144 public Register[] getCallerSaveRegisters() { 145 return callerSaved; 146 } 147 148 @Override 149 public boolean areAllAllocatableRegistersCallerSaved() { 150 return allAllocatableAreCallerSaved; 151 } 152 153 @Override 154 public Register getRegisterForRole(int index) { 155 throw new UnsupportedOperationException(); 156 } 157 158 @Override 159 public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target, boolean stackOnly) { 160 if (type == Type.NativeCall) { 161 return callingConvention(nativeGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly); 162 } 163 // On x64, parameter locations are the same whether viewed 164 // from the caller or callee perspective 165 return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly); 166 } 167 168 public Register[] getCallingConventionRegisters(Type type, Kind kind) { 169 if (architecture.canStoreValue(XMM, kind)) { 170 return xmmParameterRegisters; 171 } 172 assert architecture.canStoreValue(CPU, kind); 173 return type == Type.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters; 174 } 175 176 private CallingConvention callingConvention(Register[] generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, Type type, TargetDescription target, boolean stackOnly) { 177 AllocatableValue[] locations = new AllocatableValue[parameterTypes.length]; 178 179 int currentGeneral = 0; 180 int currentXMM = 0; 181 int currentStackOffset = type == Type.NativeCall && needsNativeStackHomeSpace ? generalParameterRegisters.length * target.wordSize : 0; 182 183 for (int i = 0; i < parameterTypes.length; i++) { 184 final Kind kind = parameterTypes[i].getKind(); 185 186 switch (kind) { 187 case Byte: 188 case Boolean: 189 case Short: 190 case Char: 191 case Int: 192 case Long: 193 case Object: 194 if (!stackOnly && currentGeneral < generalParameterRegisters.length) { 195 Register register = generalParameterRegisters[currentGeneral++]; 196 locations[i] = register.asValue(target.getLIRKind(kind)); 197 } 198 break; 199 case Float: 200 case Double: 201 if (!stackOnly && currentXMM < xmmParameterRegisters.length) { 202 Register register = xmmParameterRegisters[currentXMM++]; 203 locations[i] = register.asValue(target.getLIRKind(kind)); 204 } 205 break; 206 default: 207 throw JVMCIError.shouldNotReachHere(); 208 } 209 210 if (locations[i] == null) { 211 locations[i] = StackSlot.get(target.getLIRKind(kind.getStackKind()), currentStackOffset, !type.out); 212 currentStackOffset += Math.max(target.getSizeInBytes(kind), target.wordSize); 213 } 214 } 215 216 Kind returnKind = returnType == null ? Kind.Void : returnType.getKind(); 217 AllocatableValue returnLocation = returnKind == Kind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(target.getLIRKind(returnKind.getStackKind())); 218 return new CallingConvention(currentStackOffset, returnLocation, locations); 219 } 220 221 @Override 222 public Register getReturnRegister(Kind kind) { 223 switch (kind) { 224 case Boolean: 225 case Byte: 226 case Char: 227 case Short: 228 case Int: 229 case Long: 230 case Object: 231 return rax; 232 case Float: 233 case Double: 234 return xmm0; 235 case Void: 236 case Illegal: 237 return null; 238 default: 239 throw new UnsupportedOperationException("no return register for type " + kind); 240 } 241 } 242 243 @Override 244 public Register getFrameRegister() { 245 return rsp; 246 } 247 248 public CalleeSaveLayout getCalleeSaveLayout() { 249 return csl; 250 } 251 252 @Override 253 public String toString() { 254 return String.format("Allocatable: " + Arrays.toString(getAllocatableRegisters()) + "%n" + "CallerSave: " + Arrays.toString(getCallerSaveRegisters()) + "%n"); 255 } 256}