001/* 002 * Copyright (c) 2011, 2012, 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; 024 025import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; 026import static com.oracle.graal.lir.LIRValueUtil.*; 027 028import java.util.*; 029 030import com.oracle.graal.asm.*; 031import com.oracle.graal.compiler.common.cfg.*; 032import com.oracle.graal.lir.asm.*; 033import com.oracle.graal.lir.framemap.*; 034 035import jdk.internal.jvmci.code.*; 036import jdk.internal.jvmci.common.*; 037import jdk.internal.jvmci.meta.*; 038 039/** 040 * A collection of machine-independent LIR operations, as well as interfaces to be implemented for 041 * specific kinds or LIR operations. 042 */ 043public class StandardOp { 044 045 /** 046 * A block delimiter. Every well formed block must contain exactly one such operation and it 047 * must be the last operation in the block. 048 */ 049 public interface BlockEndOp { 050 void setOutgoingValues(Value[] values); 051 052 int getOutgoingSize(); 053 054 Value getOutgoingValue(int idx); 055 056 int addOutgoingValues(Value[] values); 057 058 void clearOutgoingValues(); 059 } 060 061 public interface NullCheck { 062 Value getCheckedValue(); 063 064 LIRFrameState getState(); 065 } 066 067 public interface ImplicitNullCheck { 068 boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit); 069 } 070 071 /** 072 * LIR operation that defines the position of a label. 073 */ 074 public static final class LabelOp extends LIRInstruction { 075 public static final LIRInstructionClass<LabelOp> TYPE = LIRInstructionClass.create(LabelOp.class); 076 077 /** 078 * In the LIR, every register and variable must be defined before it is used. For method 079 * parameters that are passed in fixed registers, exception objects passed to the exception 080 * handler in a fixed register, or any other use of a fixed register not defined in this 081 * method, an artificial definition is necessary. To avoid spill moves to be inserted 082 * between the label at the beginning of a block an an actual definition in the second 083 * instruction of a block, the registers are defined here in the label. 084 */ 085 @Def({REG, STACK}) private Value[] incomingValues; 086 private int size; 087 088 private final Label label; 089 private final boolean align; 090 091 public LabelOp(Label label, boolean align) { 092 super(TYPE); 093 this.label = label; 094 this.align = align; 095 this.incomingValues = Value.NO_VALUES; 096 size = 0; 097 } 098 099 public void setIncomingValues(Value[] values) { 100 assert this.incomingValues.length == 0; 101 assert values != null; 102 this.incomingValues = values; 103 size = values.length; 104 } 105 106 public int getIncomingSize() { 107 return size; 108 } 109 110 public Value getIncomingValue(int idx) { 111 assert checkRange(idx); 112 return incomingValues[idx]; 113 } 114 115 public void clearIncomingValues() { 116 incomingValues = Value.NO_VALUES; 117 size = 0; 118 } 119 120 public void addIncomingValues(Value[] values) { 121 int t = size + values.length; 122 if (t >= incomingValues.length) { 123 Value[] newArray = new Value[t]; 124 System.arraycopy(incomingValues, 0, newArray, 0, size); 125 incomingValues = newArray; 126 } 127 System.arraycopy(values, 0, incomingValues, size, values.length); 128 size = t; 129 } 130 131 private boolean checkRange(int idx) { 132 return idx < size; 133 } 134 135 @Override 136 public void emitCode(CompilationResultBuilder crb) { 137 if (align) { 138 crb.asm.align(crb.target.wordSize * 2); 139 } 140 crb.asm.bind(label); 141 } 142 143 public Label getLabel() { 144 return label; 145 } 146 147 /** 148 * @return true if this label acts as a PhiIn. 149 */ 150 public boolean isPhiIn() { 151 return getIncomingSize() > 0 && isVariable(getIncomingValue(0)); 152 } 153 } 154 155 public abstract static class AbstractBlockEndOp extends LIRInstruction implements BlockEndOp { 156 public static final LIRInstructionClass<AbstractBlockEndOp> TYPE = LIRInstructionClass.create(AbstractBlockEndOp.class); 157 158 @Alive({REG, STACK, CONST}) private Value[] outgoingValues; 159 private int size; 160 161 protected AbstractBlockEndOp(LIRInstructionClass<? extends AbstractBlockEndOp> c) { 162 super(c); 163 this.outgoingValues = Value.NO_VALUES; 164 size = 0; 165 } 166 167 public void setOutgoingValues(Value[] values) { 168 assert this.outgoingValues.length == 0; 169 assert values != null; 170 this.outgoingValues = values; 171 size = values.length; 172 } 173 174 public int getOutgoingSize() { 175 return size; 176 } 177 178 public Value getOutgoingValue(int idx) { 179 assert checkRange(idx); 180 return outgoingValues[idx]; 181 } 182 183 public void clearOutgoingValues() { 184 outgoingValues = Value.NO_VALUES; 185 size = 0; 186 } 187 188 public int addOutgoingValues(Value[] values) { 189 int t = size + values.length; 190 if (t >= outgoingValues.length) { 191 Value[] newArray = new Value[t]; 192 System.arraycopy(outgoingValues, 0, newArray, 0, size); 193 outgoingValues = newArray; 194 } 195 System.arraycopy(values, 0, outgoingValues, size, values.length); 196 size = t; 197 return t; 198 } 199 200 private boolean checkRange(int idx) { 201 return idx < size; 202 } 203 } 204 205 /** 206 * LIR operation that is an unconditional jump to a {@link #destination()}. 207 */ 208 public static class JumpOp extends AbstractBlockEndOp { 209 public static final LIRInstructionClass<JumpOp> TYPE = LIRInstructionClass.create(JumpOp.class); 210 211 private final LabelRef destination; 212 213 public JumpOp(LabelRef destination) { 214 this(TYPE, destination); 215 } 216 217 protected JumpOp(LIRInstructionClass<? extends JumpOp> c, LabelRef destination) { 218 super(c); 219 this.destination = destination; 220 } 221 222 @Override 223 public void emitCode(CompilationResultBuilder crb) { 224 if (!crb.isSuccessorEdge(destination)) { 225 crb.asm.jmp(destination.label()); 226 } 227 } 228 229 public LabelRef destination() { 230 return destination; 231 } 232 } 233 234 /** 235 * Marker interface for a LIR operation that is a conditional jump. 236 */ 237 public interface BranchOp extends BlockEndOp { 238 } 239 240 /** 241 * Marker interface for a LIR operation that moves a value from {@link #getInput()} to 242 * {@link #getResult()}. 243 */ 244 public interface MoveOp { 245 246 Value getInput(); 247 248 AllocatableValue getResult(); 249 } 250 251 /** 252 * An operation that saves registers to the stack. The set of saved registers can be 253 * {@linkplain #remove(Set) pruned} and a mapping from registers to the frame slots in which 254 * they are saved can be {@linkplain #getMap(FrameMap) retrieved}. 255 */ 256 public interface SaveRegistersOp { 257 258 /** 259 * Determines if the {@link #remove(Set)} operation is supported for this object. 260 */ 261 boolean supportsRemove(); 262 263 /** 264 * Prunes {@code doNotSave} from the registers saved by this operation. 265 * 266 * @param doNotSave registers that should not be saved by this operation 267 * @return the number of registers pruned 268 * @throws UnsupportedOperationException if removal is not {@linkplain #supportsRemove() 269 * supported} 270 */ 271 int remove(Set<Register> doNotSave); 272 273 /** 274 * Gets a map from the saved registers saved by this operation to the frame slots in which 275 * they are saved. 276 * 277 * @param frameMap used to {@linkplain FrameMap#offsetForStackSlot(StackSlot) convert} a 278 * virtual slot to a frame slot index 279 */ 280 RegisterSaveLayout getMap(FrameMap frameMap); 281 282 } 283 284 /** 285 * An operation that takes one input and stores it in a stack slot as well as to an ordinary 286 * variable. 287 */ 288 public interface StackStoreOp { 289 290 Value getInput(); 291 292 AllocatableValue getResult(); 293 294 StackSlotValue getStackSlot(); 295 } 296 297 /** 298 * A LIR operation that does nothing. If the operation records its position, it can be 299 * subsequently {@linkplain #replace(LIR, LIRInstruction) replaced}. 300 */ 301 public static final class NoOp extends LIRInstruction { 302 public static final LIRInstructionClass<NoOp> TYPE = LIRInstructionClass.create(NoOp.class); 303 304 /** 305 * The block in which this instruction is located. 306 */ 307 final AbstractBlockBase<?> block; 308 309 /** 310 * The block index of this instruction. 311 */ 312 final int index; 313 314 public NoOp(AbstractBlockBase<?> block, int index) { 315 super(TYPE); 316 this.block = block; 317 this.index = index; 318 } 319 320 public void replace(LIR lir, LIRInstruction replacement) { 321 List<LIRInstruction> instructions = lir.getLIRforBlock(block); 322 assert instructions.get(index).equals(this) : String.format("Replacing the wrong instruction: %s instead of %s", instructions.get(index), this); 323 instructions.set(index, replacement); 324 } 325 326 public void remove(LIR lir) { 327 List<LIRInstruction> instructions = lir.getLIRforBlock(block); 328 assert instructions.get(index).equals(this) : String.format("Removing the wrong instruction: %s instead of %s", instructions.get(index), this); 329 instructions.remove(index); 330 } 331 332 @Override 333 public void emitCode(CompilationResultBuilder crb) { 334 if (block != null) { 335 throw new JVMCIError(this + " should have been replaced"); 336 } 337 } 338 } 339 340 @Opcode("BLACKHOLE") 341 public static final class BlackholeOp extends LIRInstruction { 342 public static final LIRInstructionClass<BlackholeOp> TYPE = LIRInstructionClass.create(BlackholeOp.class); 343 344 @Use({REG, STACK, CONST}) private Value value; 345 346 public BlackholeOp(Value value) { 347 super(TYPE); 348 this.value = value; 349 } 350 351 @Override 352 public void emitCode(CompilationResultBuilder crb) { 353 // do nothing, just keep value alive until at least here 354 } 355 } 356 357 public static final class StackMove extends LIRInstruction implements MoveOp { 358 public static final LIRInstructionClass<StackMove> TYPE = LIRInstructionClass.create(StackMove.class); 359 360 @Def({STACK, HINT}) protected AllocatableValue result; 361 @Use({STACK}) protected Value input; 362 363 public StackMove(AllocatableValue result, Value input) { 364 super(TYPE); 365 this.result = result; 366 this.input = input; 367 } 368 369 @Override 370 public void emitCode(CompilationResultBuilder crb) { 371 throw new JVMCIError(this + " should have been removed"); 372 } 373 374 @Override 375 public Value getInput() { 376 return input; 377 } 378 379 @Override 380 public AllocatableValue getResult() { 381 return result; 382 } 383 } 384 385}