1 /* 2 * Copyright (c) 2013, 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.sparc; 24 25 import static jdk.vm.ci.sparc.SPARC.*; 26 27 import java.util.*; 28 29 import jdk.vm.ci.code.*; 30 import jdk.vm.ci.code.CallingConvention.*; 31 import jdk.vm.ci.common.*; 32 import jdk.vm.ci.hotspot.*; 33 import jdk.vm.ci.meta.*; 34 import jdk.vm.ci.sparc.*; 35 36 public class SPARCHotSpotRegisterConfig implements RegisterConfig { 37 38 private final Architecture architecture; 39 40 private final Register[] allocatable; 41 42 private final RegisterAttributes[] attributesMap; 43 44 @Override 45 public Register[] getAllocatableRegisters() { 46 return allocatable.clone(); 47 } 48 49 public Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers) { 50 ArrayList<Register> list = new ArrayList<>(); 51 for (Register reg : registers) { 52 if (architecture.canStoreValue(reg.getRegisterCategory(), kind)) { 53 // Special treatment for double precision 54 // TODO: This is wasteful it uses only half of the registers as float. 55 if (kind == JavaKind.Double) { 56 if (reg.getRegisterCategory().equals(FPUd)) { 57 list.add(reg); 58 } 59 } else if (kind == JavaKind.Float) { 60 if (reg.getRegisterCategory().equals(FPUs)) { 61 list.add(reg); 62 } 63 } else { 64 list.add(reg); 65 } 66 } 67 } 68 69 Register[] ret = list.toArray(new Register[list.size()]); 70 return ret; 71 } 72 73 @Override 74 public RegisterAttributes[] getAttributesMap() { 75 return attributesMap.clone(); 76 } 77 78 private final Register[] cpuCallerParameterRegisters = {o0, o1, o2, o3, o4, o5}; 79 private final Register[] cpuCalleeParameterRegisters = {i0, i1, i2, i3, i4, i5}; 80 81 private final Register[] fpuParameterRegisters = {f0, f1, f2, f3, f4, f5, f6, f7}; 82 private final Register[] fpuDoubleParameterRegisters = {d0, null, d2, null, d4, null, d6, null}; 83 // @formatter:off 84 private final Register[] callerSaveRegisters = 85 {g1, g2, g3, g4, g5, g6, g7, 86 o0, o1, o2, o3, o4, o5, o7, 87 f0, f1, f2, f3, f4, f5, f6, f7, 88 f8, f9, f10, f11, f12, f13, f14, f15, 89 f16, f17, f18, f19, f20, f21, f22, f23, 90 f24, f25, f26, f27, f28, f29, f30, f31, 91 d32, d34, d36, d38, d40, d42, d44, d46, 92 d48, d50, d52, d54, d56, d58, d60, d62}; 93 // @formatter:on 94 95 /** 96 * Registers saved by the callee. This lists all L and I registers which are saved in the 97 * register window. 98 */ 99 private final Register[] calleeSaveRegisters = {l0, l1, l2, l3, l4, l5, l6, l7, i0, i1, i2, i3, i4, i5, i6, i7}; 100 101 private static Register[] initAllocatable(boolean reserveForHeapBase) { 102 Register[] registers = null; 103 if (reserveForHeapBase) { 104 // @formatter:off 105 registers = new Register[]{ 106 // TODO this is not complete 107 // o7 cannot be used as register because it is always overwritten on call 108 // and the current register handler would ignore this fact if the called 109 // method still does not modify registers, in fact o7 is modified by the Call instruction 110 // There would be some extra handlin necessary to be able to handle the o7 properly for local usage 111 g1, g4, g5, 112 o0, o1, o2, o3, o4, o5, /*o6,o7,*/ 113 l0, l1, l2, l3, l4, l5, l6, l7, 114 i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/ 115 //f0, f1, f2, f3, f4, f5, f6, f7, 116 f8, f9, f10, f11, f12, f13, f14, f15, 117 f16, f17, f18, f19, f20, f21, f22, f23, 118 f24, f25, f26, f27, f28, f29, f30, f31, 119 d32, d34, d36, d38, d40, d42, d44, d46, 120 d48, d50, d52, d54, d56, d58, d60, d62 121 }; 122 // @formatter:on 123 } else { 124 // @formatter:off 125 registers = new Register[]{ 126 // TODO this is not complete 127 g1, g4, g5, 128 o0, o1, o2, o3, o4, o5, /*o6, o7,*/ 129 l0, l1, l2, l3, l4, l5, l6, l7, 130 i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/ 131 // f0, f1, f2, f3, f4, f5, f6, f7 132 f8, f9, f10, f11, f12, f13, f14, f15, 133 f16, f17, f18, f19, f20, f21, f22, f23, 134 f24, f25, f26, f27, f28, f29, f30, f31, 135 d32, d34, d36, d38, d40, d42, d44, d46, 136 d48, d50, d52, d54, d56, d58, d60, d62 137 }; 138 // @formatter:on 139 } 140 141 return registers; 142 } 143 144 public SPARCHotSpotRegisterConfig(TargetDescription target, HotSpotVMConfig config) { 145 this(target, initAllocatable(config.useCompressedOops)); 146 } 147 148 public SPARCHotSpotRegisterConfig(TargetDescription target, Register[] allocatable) { 149 this.architecture = target.arch; 150 this.allocatable = allocatable.clone(); 151 attributesMap = RegisterAttributes.createMap(this, SPARC.allRegisters); 152 } 153 154 @Override 155 public Register[] getCallerSaveRegisters() { 156 return callerSaveRegisters; 157 } 158 159 public Register[] getCalleeSaveRegisters() { 160 return calleeSaveRegisters; 161 } 162 163 @Override 164 public boolean areAllAllocatableRegistersCallerSaved() { 165 return false; 166 } 167 168 @Override 169 public Register getRegisterForRole(int index) { 170 throw new UnsupportedOperationException(); 171 } 172 173 @Override 174 public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target, boolean stackOnly) { 175 if (type == Type.JavaCall || type == Type.NativeCall) { 176 return callingConvention(cpuCallerParameterRegisters, returnType, parameterTypes, type, target, stackOnly); 177 } 178 if (type == Type.JavaCallee) { 179 return callingConvention(cpuCalleeParameterRegisters, returnType, parameterTypes, type, target, stackOnly); 180 } 181 throw JVMCIError.shouldNotReachHere(); 182 } 183 184 public Register[] getCallingConventionRegisters(Type type, JavaKind kind) { 185 if (architecture.canStoreValue(FPUs, kind) || architecture.canStoreValue(FPUd, kind)) { 186 return fpuParameterRegisters; 187 } 188 assert architecture.canStoreValue(CPU, kind); 189 return type == Type.JavaCallee ? cpuCalleeParameterRegisters : cpuCallerParameterRegisters; 190 } 191 192 private CallingConvention callingConvention(Register[] generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, Type type, TargetDescription target, boolean stackOnly) { 193 AllocatableValue[] locations = new AllocatableValue[parameterTypes.length]; 194 195 int currentGeneral = 0; 196 int currentFloating = 0; 197 int currentStackOffset = 0; 198 199 for (int i = 0; i < parameterTypes.length; i++) { 200 final JavaKind kind = parameterTypes[i].getJavaKind().getStackKind(); 201 202 switch (kind) { 203 case Byte: 204 case Boolean: 205 case Short: 206 case Char: 207 case Int: 208 case Long: 209 case Object: 210 if (!stackOnly && currentGeneral < generalParameterRegisters.length) { 211 Register register = generalParameterRegisters[currentGeneral++]; 212 locations[i] = register.asValue(target.getLIRKind(kind)); 213 } 214 break; 215 case Double: 216 if (!stackOnly && currentFloating < fpuParameterRegisters.length) { 217 if (currentFloating % 2 != 0) { 218 // Make register number even to be a double reg 219 currentFloating++; 220 } 221 Register register = fpuDoubleParameterRegisters[currentFloating]; 222 currentFloating += 2; // Only every second is a double register 223 locations[i] = register.asValue(target.getLIRKind(kind)); 224 } 225 break; 226 case Float: 227 if (!stackOnly && currentFloating < fpuParameterRegisters.length) { 228 Register register = fpuParameterRegisters[currentFloating++]; 229 locations[i] = register.asValue(target.getLIRKind(kind)); 230 } 231 break; 232 default: 233 throw JVMCIError.shouldNotReachHere(); 234 } 235 236 if (locations[i] == null) { 237 // Stack slot is always aligned to its size in bytes but minimum wordsize 238 int typeSize = SPARC.spillSlotSize(target, kind); 239 currentStackOffset = roundUp(currentStackOffset, typeSize); 240 int slotOffset = currentStackOffset + SPARC.REGISTER_SAFE_AREA_SIZE; 241 locations[i] = StackSlot.get(target.getLIRKind(kind.getStackKind()), slotOffset, !type.out); 242 currentStackOffset += typeSize; 243 } 244 } 245 246 JavaKind returnKind = returnType == null ? JavaKind.Void : returnType.getJavaKind(); 247 AllocatableValue returnLocation = returnKind == JavaKind.Void ? Value.ILLEGAL : getReturnRegister(returnKind, type).asValue(target.getLIRKind(returnKind.getStackKind())); 248 // Space where callee may spill outgoing parameters o0...o5 249 int lowerOutgoingSpace = Math.min(locations.length, 6) * target.wordSize; 250 return new CallingConvention(currentStackOffset + lowerOutgoingSpace, returnLocation, locations); 251 } 252 253 private static int roundUp(int number, int mod) { 254 return ((number + mod - 1) / mod) * mod; 255 } 256 257 @Override 258 public Register getReturnRegister(JavaKind kind) { 259 return getReturnRegister(kind, Type.JavaCallee); 260 } 261 262 private static Register getReturnRegister(JavaKind kind, Type type) { 263 switch (kind) { 264 case Boolean: 265 case Byte: 266 case Char: 267 case Short: 268 case Int: 269 case Long: 270 case Object: 271 return type == Type.JavaCallee ? i0 : o0; 272 case Float: 273 return f0; 274 case Double: 275 return d0; 276 case Void: 277 case Illegal: 278 return null; 279 default: 280 throw new UnsupportedOperationException("no return register for type " + kind); 281 } 282 } 283 284 @Override 285 public Register getFrameRegister() { 286 return sp; 287 } 288 289 @Override 290 public String toString() { 291 return String.format("Allocatable: " + Arrays.toString(getAllocatableRegisters()) + "%n" + "CallerSave: " + Arrays.toString(getCallerSaveRegisters()) + "%n"); 292 } 293 }