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 }