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