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