001/* 002 * Copyright (c) 2013, 2014, 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.sparc; 024 025import static jdk.internal.jvmci.sparc.SPARC.*; 026 027import java.util.*; 028 029import jdk.internal.jvmci.code.*; 030import jdk.internal.jvmci.code.CallingConvention.*; 031import jdk.internal.jvmci.common.*; 032import jdk.internal.jvmci.hotspot.*; 033import jdk.internal.jvmci.meta.*; 034import jdk.internal.jvmci.sparc.*; 035 036public class SPARCHotSpotRegisterConfig implements RegisterConfig { 037 038 private final Architecture architecture; 039 040 private final Register[] allocatable; 041 042 private final RegisterAttributes[] attributesMap; 043 044 @Override 045 public Register[] getAllocatableRegisters() { 046 return allocatable.clone(); 047 } 048 049 public Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers) { 050 ArrayList<Register> list = new ArrayList<>(); 051 for (Register reg : registers) { 052 if (architecture.canStoreValue(reg.getRegisterCategory(), kind)) { 053 // Special treatment for double precision 054 // TODO: This is wasteful it uses only half of the registers as float. 055 if (kind == Kind.Double) { 056 if (reg.name.startsWith("d")) { 057 list.add(reg); 058 } 059 } else if (kind == Kind.Float) { 060 if (reg.name.startsWith("f")) { 061 list.add(reg); 062 } 063 } else { 064 list.add(reg); 065 } 066 } 067 } 068 069 Register[] ret = list.toArray(new Register[list.size()]); 070 return ret; 071 } 072 073 @Override 074 public RegisterAttributes[] getAttributesMap() { 075 return attributesMap.clone(); 076 } 077 078 private final Register[] cpuCallerParameterRegisters = {o0, o1, o2, o3, o4, o5}; 079 private final Register[] cpuCalleeParameterRegisters = {i0, i1, i2, i3, i4, i5}; 080 081 private final Register[] fpuParameterRegisters = {f0, f1, f2, f3, f4, f5, f6, f7}; 082 private final Register[] fpuDoubleParameterRegisters = {d0, null, d2, null, d4, null, d6, null}; 083 // @formatter:off 084 private final Register[] callerSaveRegisters = 085 {g1, g2, g3, g4, g5, g6, g7, 086 o0, o1, o2, o3, o4, o5, o7, 087 f0, f1, f2, f3, f4, f5, f6, f7, 088 f8, f9, f10, f11, f12, f13, f14, f15, 089 f16, f17, f18, f19, f20, f21, f22, f23, 090 f24, f25, f26, f27, f28, f29, f30, f31, 091 d32, d34, d36, d38, d40, d42, d44, d46, 092 d48, d50, d52, d54, d56, d58, d60, d62}; 093 // @formatter:on 094 095 /** 096 * Registers saved by the callee. This lists all L and I registers which are saved in the 097 * register window. 098 */ 099 private final Register[] calleeSaveRegisters = {l0, l1, l2, l3, l4, l5, l6, l7, i0, i1, i2, i3, i4, i5, i6, i7}; 100 101 private final CalleeSaveLayout csl; 102 103 private static Register[] initAllocatable(boolean reserveForHeapBase) { 104 Register[] registers = null; 105 if (reserveForHeapBase) { 106 // @formatter:off 107 registers = new Register[]{ 108 // TODO this is not complete 109 // o7 cannot be used as register because it is always overwritten on call 110 // and the current register handler would ignore this fact if the called 111 // method still does not modify registers, in fact o7 is modified by the Call instruction 112 // There would be some extra handlin necessary to be able to handle the o7 properly for local usage 113 g1, g4, g5, 114 o0, o1, o2, o3, o4, o5, /*o6,o7,*/ 115 l0, l1, l2, l3, l4, l5, l6, l7, 116 i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/ 117 //f0, f1, f2, f3, f4, f5, f6, f7, 118 f8, f9, f10, f11, f12, f13, f14, f15, 119 f16, f17, f18, f19, f20, f21, f22, f23, 120 f24, f25, f26, f27, f28, f29, f30, f31, 121 d32, d34, d36, d38, d40, d42, d44, d46, 122 d48, d50, d52, d54, d56, d58, d60, d62 123 }; 124 // @formatter:on 125 } else { 126 // @formatter:off 127 registers = new Register[]{ 128 // TODO this is not complete 129 g1, g4, g5, 130 o0, o1, o2, o3, o4, o5, /*o6, o7,*/ 131 l0, l1, l2, l3, l4, l5, l6, l7, 132 i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/ 133// f0, f1, f2, f3, f4, f5, f6, f7 134 f8, f9, f10, f11, f12, f13, f14, f15, 135 f16, f17, f18, f19, f20, f21, f22, f23, 136 f24, f25, f26, f27, f28, f29, f30, f31, 137 d32, d34, d36, d38, d40, d42, d44, d46, 138 d48, d50, d52, d54, d56, d58, d60, d62 139 }; 140 // @formatter:on 141 } 142 143 return registers; 144 } 145 146 public SPARCHotSpotRegisterConfig(TargetDescription target, HotSpotVMConfig config) { 147 this(target, initAllocatable(config.useCompressedOops)); 148 } 149 150 public SPARCHotSpotRegisterConfig(TargetDescription target, Register[] allocatable) { 151 this.architecture = target.arch; 152 153 csl = new CalleeSaveLayout(target, -1, -1, target.arch.getWordSize(), calleeSaveRegisters); 154 this.allocatable = allocatable.clone(); 155 attributesMap = RegisterAttributes.createMap(this, SPARC.allRegisters); 156 } 157 158 @Override 159 public Register[] getCallerSaveRegisters() { 160 return callerSaveRegisters; 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, Kind 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 Kind kind = parameterTypes[i].getKind(); 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 Kind returnKind = returnType == null ? Kind.Void : returnType.getKind(); 247 AllocatableValue returnLocation = returnKind == Kind.Void ? Value.ILLEGAL : getReturnRegister(returnKind, type).asValue(target.getLIRKind(returnKind.getStackKind())); 248 return new CallingConvention(currentStackOffset, returnLocation, locations); 249 } 250 251 private static int roundUp(int number, int mod) { 252 return ((number + mod - 1) / mod) * mod; 253 } 254 255 @Override 256 public Register getReturnRegister(Kind kind) { 257 return getReturnRegister(kind, Type.JavaCallee); 258 } 259 260 private static Register getReturnRegister(Kind kind, Type type) { 261 switch (kind) { 262 case Boolean: 263 case Byte: 264 case Char: 265 case Short: 266 case Int: 267 case Long: 268 case Object: 269 return type == Type.JavaCallee ? i0 : o0; 270 case Float: 271 return f0; 272 case Double: 273 return d0; 274 case Void: 275 case Illegal: 276 return null; 277 default: 278 throw new UnsupportedOperationException("no return register for type " + kind); 279 } 280 } 281 282 @Override 283 public Register getFrameRegister() { 284 return sp; 285 } 286 287 public CalleeSaveLayout getCalleeSaveLayout() { 288 return csl; 289 } 290 291 @Override 292 public String toString() { 293 return String.format("Allocatable: " + Arrays.toString(getAllocatableRegisters()) + "%n" + "CallerSave: " + Arrays.toString(getCallerSaveRegisters()) + "%n"); 294 } 295}