1/*
2 * Copyright (c) 2014, 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 */
23package org.graalvm.compiler.lir.sparc;
24
25import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
26import static org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer.DUMMY;
27import static jdk.vm.ci.code.ValueUtil.asStackSlot;
28import static jdk.vm.ci.code.ValueUtil.isStackSlot;
29
30import java.util.Arrays;
31import java.util.Set;
32
33import org.graalvm.compiler.asm.sparc.SPARCAddress;
34import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
35import org.graalvm.compiler.lir.LIRInstructionClass;
36import org.graalvm.compiler.lir.LIRValueUtil;
37import org.graalvm.compiler.lir.Opcode;
38import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
39import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
40import org.graalvm.compiler.lir.framemap.FrameMap;
41
42import jdk.vm.ci.code.Register;
43import jdk.vm.ci.code.RegisterSaveLayout;
44import jdk.vm.ci.code.RegisterValue;
45import jdk.vm.ci.code.StackSlot;
46import jdk.vm.ci.meta.AllocatableValue;
47import jdk.vm.ci.sparc.SPARC;
48
49/**
50 * Saves registers to stack slots.
51 */
52@Opcode("SAVE_REGISTER")
53public class SPARCSaveRegistersOp extends SPARCLIRInstruction implements SaveRegistersOp {
54    public static final LIRInstructionClass<SPARCSaveRegistersOp> TYPE = LIRInstructionClass.create(SPARCSaveRegistersOp.class);
55    public static final Register RETURN_REGISTER_STORAGE = SPARC.d62;
56    public static final SizeEstimate SIZE = SizeEstimate.create(32);
57    /**
58     * The registers (potentially) saved by this operation.
59     */
60    protected final Register[] savedRegisters;
61
62    /**
63     * The slots to which the registers are saved.
64     */
65    @Def(STACK) protected final AllocatableValue[] slots;
66
67    /**
68     * Specifies if {@link #remove(Set)} should have an effect.
69     */
70    protected final boolean supportsRemove;
71
72    /**
73     *
74     * @param savedRegisters the registers saved by this operation which may be subject to
75     *            {@linkplain #remove(Set) pruning}
76     * @param savedRegisterLocations the slots to which the registers are saved
77     * @param supportsRemove determines if registers can be {@linkplain #remove(Set) pruned}
78     */
79    public SPARCSaveRegistersOp(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) {
80        super(TYPE, SIZE);
81        assert Arrays.asList(savedRegisterLocations).stream().allMatch(LIRValueUtil::isVirtualStackSlot);
82        this.savedRegisters = savedRegisters;
83        this.slots = savedRegisterLocations;
84        this.supportsRemove = supportsRemove;
85    }
86
87    @Override
88    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
89        // Can be used with VIS3
90        // new Movxtod(SPARC.i0, RETURN_REGISTER_STORAGE).emit(masm);
91        // We abuse the first stackslot for transferring i0 to return_register_storage
92        // assert slots.length >= 1;
93        SPARCAddress slot0Address = (SPARCAddress) crb.asAddress(slots[0]);
94        masm.stx(SPARC.i0, slot0Address);
95        masm.lddf(slot0Address, RETURN_REGISTER_STORAGE);
96
97        // Now save the registers
98        for (int i = 0; i < savedRegisters.length; i++) {
99            if (savedRegisters[i] != null) {
100                assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i];
101                Register savedRegister = savedRegisters[i];
102                StackSlot slot = asStackSlot(slots[i]);
103                SPARCAddress slotAddress = (SPARCAddress) crb.asAddress(slot);
104                RegisterValue input = savedRegister.asValue(slot.getValueKind());
105                SPARCMove.emitStore(input, slotAddress, slot.getPlatformKind(), DUMMY, null, crb, masm);
106            }
107        }
108    }
109
110    public AllocatableValue[] getSlots() {
111        return slots;
112    }
113
114    @Override
115    public boolean supportsRemove() {
116        return supportsRemove;
117    }
118
119    @Override
120    public int remove(Set<Register> doNotSave) {
121        if (!supportsRemove) {
122            throw new UnsupportedOperationException();
123        }
124        return prune(doNotSave, savedRegisters);
125    }
126
127    static int prune(Set<Register> toRemove, Register[] registers) {
128        int pruned = 0;
129        for (int i = 0; i < registers.length; i++) {
130            if (registers[i] != null) {
131                if (toRemove.contains(registers[i])) {
132                    registers[i] = null;
133                    pruned++;
134                }
135            }
136        }
137        return pruned;
138    }
139
140    @Override
141    public RegisterSaveLayout getMap(FrameMap frameMap) {
142        int total = 0;
143        for (int i = 0; i < savedRegisters.length; i++) {
144            if (savedRegisters[i] != null) {
145                total++;
146            }
147        }
148        Register[] keys = new Register[total];
149        int[] values = new int[total];
150        if (total != 0) {
151            int mapIndex = 0;
152            for (int i = 0; i < savedRegisters.length; i++) {
153                if (savedRegisters[i] != null) {
154                    keys[mapIndex] = savedRegisters[i];
155                    assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i];
156                    StackSlot slot = asStackSlot(slots[i]);
157                    values[mapIndex] = indexForStackSlot(frameMap, slot);
158                    mapIndex++;
159                }
160            }
161            assert mapIndex == total;
162        }
163        return new RegisterSaveLayout(keys, values);
164    }
165
166    /**
167     * Computes the index of a stack slot relative to slot 0. This is also the bit index of stack
168     * slots in the reference map.
169     *
170     * @param slot a stack slot
171     * @return the index of the stack slot
172     */
173    private static int indexForStackSlot(FrameMap frameMap, StackSlot slot) {
174        assert frameMap.offsetForStackSlot(slot) % frameMap.getTarget().wordSize == 0;
175        int value = frameMap.offsetForStackSlot(slot) / frameMap.getTarget().wordSize;
176        return value;
177    }
178}
179