001/*
002 * Copyright (c) 2014, 2015, 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 com.oracle.graal.lir.sparc;
024
025import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
026import static com.oracle.graal.lir.sparc.SPARCDelayedControlTransfer.*;
027import static jdk.internal.jvmci.code.ValueUtil.*;
028
029import java.util.*;
030
031import jdk.internal.jvmci.code.*;
032import jdk.internal.jvmci.sparc.*;
033
034import com.oracle.graal.asm.sparc.*;
035import com.oracle.graal.lir.*;
036import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
037import com.oracle.graal.lir.asm.*;
038import com.oracle.graal.lir.framemap.*;
039
040/**
041 * Saves registers to stack slots.
042 */
043@Opcode("SAVE_REGISTER")
044public class SPARCSaveRegistersOp extends SPARCLIRInstruction implements SaveRegistersOp {
045    public static final LIRInstructionClass<SPARCSaveRegistersOp> TYPE = LIRInstructionClass.create(SPARCSaveRegistersOp.class);
046    public static final Register RETURN_REGISTER_STORAGE = SPARC.d62;
047    public static final SizeEstimate SIZE = SizeEstimate.create(32);
048    /**
049     * The registers (potentially) saved by this operation.
050     */
051    protected final Register[] savedRegisters;
052
053    /**
054     * The slots to which the registers are saved.
055     */
056    @Def(STACK) protected final StackSlotValue[] slots;
057
058    /**
059     * Specifies if {@link #remove(Set)} should have an effect.
060     */
061    protected final boolean supportsRemove;
062
063    /**
064     *
065     * @param savedRegisters the registers saved by this operation which may be subject to
066     *            {@linkplain #remove(Set) pruning}
067     * @param savedRegisterLocations the slots to which the registers are saved
068     * @param supportsRemove determines if registers can be {@linkplain #remove(Set) pruned}
069     */
070    public SPARCSaveRegistersOp(Register[] savedRegisters, StackSlotValue[] savedRegisterLocations, boolean supportsRemove) {
071        super(TYPE, SIZE);
072        assert Arrays.asList(savedRegisterLocations).stream().allMatch(ValueUtil::isVirtualStackSlot);
073        this.savedRegisters = savedRegisters;
074        this.slots = savedRegisterLocations;
075        this.supportsRemove = supportsRemove;
076    }
077
078    @Override
079    public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
080        // Can be used with VIS3
081        // new Movxtod(SPARC.i0, RETURN_REGISTER_STORAGE).emit(masm);
082        // We abuse the first stackslot for transferring i0 to return_register_storage
083        // assert slots.length >= 1;
084        SPARCAddress slot0Address = (SPARCAddress) crb.asAddress(slots[0]);
085        masm.stx(SPARC.i0, slot0Address);
086        masm.lddf(slot0Address, RETURN_REGISTER_STORAGE);
087
088        // Now save the registers
089        for (int i = 0; i < savedRegisters.length; i++) {
090            if (savedRegisters[i] != null) {
091                assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i];
092                Register savedRegister = savedRegisters[i];
093                StackSlot slot = asStackSlot(slots[i]);
094                SPARCAddress slotAddress = (SPARCAddress) crb.asAddress(slot);
095                RegisterValue input = savedRegister.asValue(slot.getLIRKind());
096                SPARCMove.emitStore(input, slotAddress, slot.getPlatformKind(), DUMMY, null, crb, masm);
097            }
098        }
099    }
100
101    public StackSlotValue[] getSlots() {
102        return slots;
103    }
104
105    public boolean supportsRemove() {
106        return supportsRemove;
107    }
108
109    public int remove(Set<Register> doNotSave) {
110        if (!supportsRemove) {
111            throw new UnsupportedOperationException();
112        }
113        return prune(doNotSave, savedRegisters);
114    }
115
116    static int prune(Set<Register> toRemove, Register[] registers) {
117        int pruned = 0;
118        for (int i = 0; i < registers.length; i++) {
119            if (registers[i] != null) {
120                if (toRemove.contains(registers[i])) {
121                    registers[i] = null;
122                    pruned++;
123                }
124            }
125        }
126        return pruned;
127    }
128
129    public RegisterSaveLayout getMap(FrameMap frameMap) {
130        int total = 0;
131        for (int i = 0; i < savedRegisters.length; i++) {
132            if (savedRegisters[i] != null) {
133                total++;
134            }
135        }
136        Register[] keys = new Register[total];
137        int[] values = new int[total];
138        if (total != 0) {
139            int mapIndex = 0;
140            for (int i = 0; i < savedRegisters.length; i++) {
141                if (savedRegisters[i] != null) {
142                    keys[mapIndex] = savedRegisters[i];
143                    assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i];
144                    StackSlot slot = asStackSlot(slots[i]);
145                    values[mapIndex] = indexForStackSlot(frameMap, slot);
146                    mapIndex++;
147                }
148            }
149            assert mapIndex == total;
150        }
151        return new RegisterSaveLayout(keys, values);
152    }
153
154    /**
155     * Computes the index of a stack slot relative to slot 0. This is also the bit index of stack
156     * slots in the reference map.
157     *
158     * @param slot a stack slot
159     * @return the index of the stack slot
160     */
161    private static int indexForStackSlot(FrameMap frameMap, StackSlot slot) {
162        assert frameMap.offsetForStackSlot(slot) % frameMap.getTarget().wordSize == 0;
163        int value = frameMap.offsetForStackSlot(slot) / frameMap.getTarget().wordSize;
164        return value;
165    }
166}