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}