22 */ |
22 */ |
23 |
23 |
24 |
24 |
25 package org.graalvm.compiler.lir; |
25 package org.graalvm.compiler.lir; |
26 |
26 |
|
27 import static jdk.vm.ci.code.ValueUtil.asStackSlot; |
|
28 import static jdk.vm.ci.code.ValueUtil.isStackSlot; |
27 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST; |
29 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST; |
28 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; |
30 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; |
29 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.OUTGOING; |
31 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.OUTGOING; |
30 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; |
32 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; |
31 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; |
33 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; |
32 |
34 |
33 import java.util.ArrayList; |
35 import java.util.ArrayList; |
|
36 import java.util.Arrays; |
34 import java.util.EnumSet; |
37 import java.util.EnumSet; |
35 |
38 |
36 import jdk.internal.vm.compiler.collections.EconomicSet; |
39 import jdk.internal.vm.compiler.collections.EconomicSet; |
|
40 import jdk.internal.vm.compiler.collections.Equivalence; |
37 import org.graalvm.compiler.asm.Label; |
41 import org.graalvm.compiler.asm.Label; |
38 import org.graalvm.compiler.core.common.GraalOptions; |
42 import org.graalvm.compiler.core.common.GraalOptions; |
39 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; |
43 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; |
40 import org.graalvm.compiler.debug.GraalError; |
44 import org.graalvm.compiler.debug.GraalError; |
41 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; |
45 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; |
298 /** |
302 /** |
299 * An operation that saves registers to the stack. The set of saved registers can be |
303 * An operation that saves registers to the stack. The set of saved registers can be |
300 * {@linkplain #remove(EconomicSet) pruned} and a mapping from registers to the frame slots in |
304 * {@linkplain #remove(EconomicSet) pruned} and a mapping from registers to the frame slots in |
301 * which they are saved can be {@linkplain #getMap(FrameMap) retrieved}. |
305 * which they are saved can be {@linkplain #getMap(FrameMap) retrieved}. |
302 */ |
306 */ |
303 public interface SaveRegistersOp { |
307 public abstract static class SaveRegistersOp extends LIRInstruction { |
304 |
308 public static final LIRInstructionClass<SaveRegistersOp> TYPE = LIRInstructionClass.create(SaveRegistersOp.class); |
305 /** |
309 |
306 * Determines if the {@link #remove(EconomicSet)} operation is supported for this object. |
310 /** |
307 */ |
311 * The registers (potentially) saved by this operation. |
308 boolean supportsRemove(); |
312 */ |
|
313 protected final Register[] savedRegisters; |
|
314 |
|
315 /** |
|
316 * The slots to which the registers are saved. |
|
317 */ |
|
318 @Def(STACK) protected final AllocatableValue[] slots; |
|
319 |
|
320 /** |
|
321 * |
|
322 * @param savedRegisters the registers saved by this operation which may be subject to |
|
323 * {@linkplain #remove(EconomicSet) pruning} |
|
324 * @param savedRegisterLocations the slots to which the registers are saved |
|
325 */ |
|
326 protected SaveRegistersOp(LIRInstructionClass<? extends SaveRegistersOp> c, Register[] savedRegisters, AllocatableValue[] savedRegisterLocations) { |
|
327 super(c); |
|
328 assert Arrays.asList(savedRegisterLocations).stream().allMatch(LIRValueUtil::isVirtualStackSlot); |
|
329 this.savedRegisters = savedRegisters; |
|
330 this.slots = savedRegisterLocations; |
|
331 } |
309 |
332 |
310 /** |
333 /** |
311 * Prunes {@code doNotSave} from the registers saved by this operation. |
334 * Prunes {@code doNotSave} from the registers saved by this operation. |
312 * |
335 * |
313 * @param doNotSave registers that should not be saved by this operation |
336 * @param doNotSave registers that should not be saved by this operation |
314 * @return the number of registers pruned |
337 * @return the number of registers pruned |
315 * @throws UnsupportedOperationException if removal is not {@linkplain #supportsRemove() |
338 */ |
316 * supported} |
339 public int remove(EconomicSet<Register> doNotSave) { |
317 */ |
340 return prune(doNotSave, savedRegisters); |
318 int remove(EconomicSet<Register> doNotSave); |
341 } |
319 |
342 |
320 /** |
343 /** |
321 * Gets a map from the saved registers saved by this operation to the frame slots in which |
344 * Gets a map from the saved registers saved by this operation to the frame slots in which |
322 * they are saved. |
345 * they are saved. |
323 * |
346 * |
324 * @param frameMap used to {@linkplain FrameMap#offsetForStackSlot(StackSlot) convert} a |
347 * @param frameMap used to {@linkplain FrameMap#offsetForStackSlot(StackSlot) convert} a |
325 * virtual slot to a frame slot index |
348 * virtual slot to a frame slot index |
326 */ |
349 */ |
327 RegisterSaveLayout getMap(FrameMap frameMap); |
350 |
328 |
351 public RegisterSaveLayout getMap(FrameMap frameMap) { |
|
352 int total = 0; |
|
353 for (int i = 0; i < savedRegisters.length; i++) { |
|
354 if (savedRegisters[i] != null) { |
|
355 total++; |
|
356 } |
|
357 } |
|
358 Register[] keys = new Register[total]; |
|
359 int[] values = new int[total]; |
|
360 if (total != 0) { |
|
361 int mapIndex = 0; |
|
362 for (int i = 0; i < savedRegisters.length; i++) { |
|
363 if (savedRegisters[i] != null) { |
|
364 keys[mapIndex] = savedRegisters[i]; |
|
365 assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i]; |
|
366 StackSlot slot = asStackSlot(slots[i]); |
|
367 values[mapIndex] = indexForStackSlot(frameMap, slot); |
|
368 mapIndex++; |
|
369 } |
|
370 } |
|
371 assert mapIndex == total; |
|
372 } |
|
373 return new RegisterSaveLayout(keys, values); |
|
374 } |
|
375 |
|
376 public Register[] getSavedRegisters() { |
|
377 return savedRegisters; |
|
378 } |
|
379 |
|
380 public EconomicSet<Register> getSaveableRegisters() { |
|
381 EconomicSet<Register> registers = EconomicSet.create(Equivalence.IDENTITY); |
|
382 for (Register r : savedRegisters) { |
|
383 registers.add(r); |
|
384 } |
|
385 return registers; |
|
386 } |
|
387 |
|
388 public AllocatableValue[] getSlots() { |
|
389 return slots; |
|
390 } |
|
391 |
|
392 @Override |
|
393 public abstract void emitCode(CompilationResultBuilder crb); |
|
394 |
|
395 static int prune(EconomicSet<Register> toRemove, Register[] registers) { |
|
396 int pruned = 0; |
|
397 for (int i = 0; i < registers.length; i++) { |
|
398 if (registers[i] != null) { |
|
399 if (toRemove.contains(registers[i])) { |
|
400 registers[i] = null; |
|
401 pruned++; |
|
402 } |
|
403 } |
|
404 } |
|
405 return pruned; |
|
406 } |
|
407 |
|
408 /** |
|
409 * Computes the index of a stack slot relative to slot 0. This is also the bit index of |
|
410 * stack slots in the reference map. |
|
411 * |
|
412 * @param slot a stack slot |
|
413 * @return the index of the stack slot |
|
414 */ |
|
415 private static int indexForStackSlot(FrameMap frameMap, StackSlot slot) { |
|
416 assert frameMap.offsetForStackSlot(slot) % frameMap.getTarget().wordSize == 0; |
|
417 int value = frameMap.offsetForStackSlot(slot) / frameMap.getTarget().wordSize; |
|
418 return value; |
|
419 } |
|
420 } |
|
421 |
|
422 /** |
|
423 * Marker interface for an operation that restores the registers saved by |
|
424 * {@link SaveRegistersOp}. |
|
425 */ |
|
426 public interface RestoreRegistersOp { |
|
427 } |
|
428 |
|
429 /** |
|
430 * Marker interface for an operation that kills some set register and stack locations. |
|
431 */ |
|
432 public interface ZapRegistersOp { |
329 } |
433 } |
330 |
434 |
331 /** |
435 /** |
332 * A LIR operation that does nothing. If the operation records its position, it can be |
436 * A LIR operation that does nothing. If the operation records its position, it can be |
333 * subsequently {@linkplain #replace(LIR, LIRInstruction) replaced}. |
437 * subsequently {@linkplain #replace(LIR, LIRInstruction) replaced}. |