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}