1 /* 2 * Copyright (c) 2011, 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 package org.graalvm.compiler.lir; 24 25 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST; 26 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; 27 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.OUTGOING; 28 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; 29 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; 30 31 import java.util.EnumSet; 32 import java.util.List; 33 import java.util.Set; 34 35 import org.graalvm.compiler.asm.Label; 36 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; 37 import org.graalvm.compiler.debug.GraalError; 38 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; 39 import org.graalvm.compiler.lir.framemap.FrameMap; 40 import org.graalvm.compiler.lir.ssa.SSAUtil; 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 import jdk.vm.ci.meta.Constant; 47 import jdk.vm.ci.meta.Value; 48 49 /** 50 * A collection of machine-independent LIR operations, as well as interfaces to be implemented for 51 * specific kinds or LIR operations. 52 */ 53 public class StandardOp { 54 55 /** 56 * A block delimiter. Every well formed block must contain exactly one such operation and it 57 * must be the last operation in the block. 58 */ 59 public interface BlockEndOp { 60 void setOutgoingValues(Value[] values); 61 62 int getOutgoingSize(); 63 64 Value getOutgoingValue(int idx); 65 66 int addOutgoingValues(Value[] values); 67 68 void clearOutgoingValues(); 69 70 void forEachOutgoingValue(InstructionValueProcedure proc); 71 72 /** 73 * The number of {@link SSAUtil phi} operands in the {@link #getOutgoingValue outgoing} 74 * array. 75 */ 76 int getPhiSize(); 77 } 78 79 public interface NullCheck { 80 Value getCheckedValue(); 81 82 LIRFrameState getState(); 83 } 84 85 public interface ImplicitNullCheck { 86 boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit); 87 } 88 89 /** 90 * LIR operation that defines the position of a label. 91 */ 92 public static final class LabelOp extends LIRInstruction { 93 public static final LIRInstructionClass<LabelOp> TYPE = LIRInstructionClass.create(LabelOp.class); 94 public static final EnumSet<OperandFlag> incomingFlags = EnumSet.of(REG, STACK); 95 96 /** 97 * In the LIR, every register and variable must be defined before it is used. For method 98 * parameters that are passed in fixed registers, exception objects passed to the exception 99 * handler in a fixed register, or any other use of a fixed register not defined in this 100 * method, an artificial definition is necessary. To avoid spill moves to be inserted 101 * between the label at the beginning of a block an an actual definition in the second 102 * instruction of a block, the registers are defined here in the label. 103 */ 104 @Def({REG, STACK}) private Value[] incomingValues; 105 private final Label label; 106 private final boolean align; 107 private int numbPhis; 108 109 public LabelOp(Label label, boolean align) { 110 super(TYPE); 111 this.label = label; 112 this.align = align; 113 this.incomingValues = Value.NO_VALUES; 114 this.numbPhis = 0; 115 } 116 117 public void setPhiValues(Value[] values) { 118 setIncomingValues(values); 119 setNumberOfPhis(values.length); 120 } 121 122 private void setNumberOfPhis(int numPhis) { 123 assert numbPhis == 0; 124 numbPhis = numPhis; 125 } 126 127 /** 128 * @see BlockEndOp#getPhiSize 129 */ 130 public int getPhiSize() { 131 return numbPhis; 132 } 133 134 public void setIncomingValues(Value[] values) { 135 assert this.incomingValues.length == 0; 136 assert values != null; 137 this.incomingValues = values; 138 } 139 140 public int getIncomingSize() { 141 return incomingValues.length; 142 } 143 144 public Value getIncomingValue(int idx) { 145 assert checkRange(idx); 146 return incomingValues[idx]; 147 } 148 149 public void clearIncomingValues() { 150 incomingValues = Value.NO_VALUES; 151 } 152 153 public void addIncomingValues(Value[] values) { 154 if (incomingValues.length == 0) { 155 setIncomingValues(values); 156 return; 157 } 158 int t = incomingValues.length + values.length; 159 Value[] newArray = new Value[t]; 160 System.arraycopy(incomingValues, 0, newArray, 0, incomingValues.length); 161 System.arraycopy(values, 0, newArray, incomingValues.length, values.length); 162 incomingValues = newArray; 163 } 164 165 private boolean checkRange(int idx) { 166 return idx < incomingValues.length; 167 } 168 169 @Override 170 public void emitCode(CompilationResultBuilder crb) { 171 if (align) { 172 crb.asm.align(crb.target.wordSize * 2); 173 } 174 crb.asm.bind(label); 175 } 176 177 public Label getLabel() { 178 return label; 179 } 180 181 /** 182 * @return true if this label acts as a PhiIn. 183 */ 184 public boolean isPhiIn() { 185 return getPhiSize() > 0; 186 } 187 188 public void forEachIncomingValue(InstructionValueProcedure proc) { 189 for (int i = 0; i < incomingValues.length; i++) { 190 incomingValues[i] = proc.doValue(this, incomingValues[i], OperandMode.DEF, incomingFlags); 191 } 192 } 193 } 194 195 public abstract static class AbstractBlockEndOp extends LIRInstruction implements BlockEndOp { 196 public static final LIRInstructionClass<AbstractBlockEndOp> TYPE = LIRInstructionClass.create(AbstractBlockEndOp.class); 197 public static final EnumSet<OperandFlag> outgoingFlags = EnumSet.of(REG, STACK, CONST, OUTGOING); 198 199 @Alive({REG, STACK, CONST, OUTGOING}) private Value[] outgoingValues; 200 private int numberOfPhis; 201 202 protected AbstractBlockEndOp(LIRInstructionClass<? extends AbstractBlockEndOp> c) { 203 super(c); 204 this.outgoingValues = Value.NO_VALUES; 205 } 206 207 public void setPhiValues(Value[] values) { 208 setOutgoingValues(values); 209 setNumberOfPhis(values.length); 210 } 211 212 private void setNumberOfPhis(int numPhis) { 213 assert numberOfPhis == 0; 214 numberOfPhis = numPhis; 215 } 216 217 @Override 218 public int getPhiSize() { 219 return numberOfPhis; 220 } 221 222 @Override 223 public void setOutgoingValues(Value[] values) { 224 assert this.outgoingValues.length == 0; 225 assert values != null; 226 this.outgoingValues = values; 227 } 228 229 @Override 230 public int getOutgoingSize() { 231 return outgoingValues.length; 232 } 233 234 @Override 235 public Value getOutgoingValue(int idx) { 236 assert checkRange(idx); 237 return outgoingValues[idx]; 238 } 239 240 @Override 241 public void clearOutgoingValues() { 242 outgoingValues = Value.NO_VALUES; 243 } 244 245 @Override 246 public int addOutgoingValues(Value[] values) { 247 if (outgoingValues.length == 0) { 248 setOutgoingValues(values); 249 return values.length; 250 } 251 int t = outgoingValues.length + values.length; 252 Value[] newArray = new Value[t]; 253 System.arraycopy(outgoingValues, 0, newArray, 0, outgoingValues.length); 254 System.arraycopy(values, 0, newArray, outgoingValues.length, values.length); 255 outgoingValues = newArray; 256 return t; 257 } 258 259 private boolean checkRange(int idx) { 260 return idx < outgoingValues.length; 261 } 262 263 @Override 264 public void forEachOutgoingValue(InstructionValueProcedure proc) { 265 for (int i = 0; i < outgoingValues.length; i++) { 266 outgoingValues[i] = proc.doValue(this, outgoingValues[i], OperandMode.ALIVE, outgoingFlags); 267 } 268 } 269 } 270 271 /** 272 * LIR operation that is an unconditional jump to a {@link #destination()}. 273 */ 274 public static class JumpOp extends AbstractBlockEndOp { 275 public static final LIRInstructionClass<JumpOp> TYPE = LIRInstructionClass.create(JumpOp.class); 276 277 private final LabelRef destination; 278 279 public JumpOp(LabelRef destination) { 280 this(TYPE, destination); 281 } 282 283 protected JumpOp(LIRInstructionClass<? extends JumpOp> c, LabelRef destination) { 284 super(c); 285 this.destination = destination; 286 } 287 288 @Override 289 public void emitCode(CompilationResultBuilder crb) { 290 if (!crb.isSuccessorEdge(destination)) { 291 crb.asm.jmp(destination.label()); 292 } 293 } 294 295 public LabelRef destination() { 296 return destination; 297 } 298 } 299 300 /** 301 * Marker interface for a LIR operation that is a conditional jump. 302 */ 303 public interface BranchOp extends BlockEndOp { 304 } 305 306 /** 307 * Marker interface for a LIR operation that moves a value to {@link #getResult()}. 308 */ 309 public interface MoveOp { 310 311 AllocatableValue getResult(); 312 } 313 314 /** 315 * Marker interface for a LIR operation that moves some non-constant value to another location. 316 */ 317 public interface ValueMoveOp extends MoveOp { 318 319 AllocatableValue getInput(); 320 } 321 322 /** 323 * Marker interface for a LIR operation that loads a {@link #getConstant()}. 324 */ 325 public interface LoadConstantOp extends MoveOp { 326 327 Constant getConstant(); 328 } 329 330 /** 331 * An operation that saves registers to the stack. The set of saved registers can be 332 * {@linkplain #remove(Set) pruned} and a mapping from registers to the frame slots in which 333 * they are saved can be {@linkplain #getMap(FrameMap) retrieved}. 334 */ 335 public interface SaveRegistersOp { 336 337 /** 338 * Determines if the {@link #remove(Set)} operation is supported for this object. 339 */ 340 boolean supportsRemove(); 341 342 /** 343 * Prunes {@code doNotSave} from the registers saved by this operation. 344 * 345 * @param doNotSave registers that should not be saved by this operation 346 * @return the number of registers pruned 347 * @throws UnsupportedOperationException if removal is not {@linkplain #supportsRemove() 348 * supported} 349 */ 350 int remove(Set<Register> doNotSave); 351 352 /** 353 * Gets a map from the saved registers saved by this operation to the frame slots in which 354 * they are saved. 355 * 356 * @param frameMap used to {@linkplain FrameMap#offsetForStackSlot(StackSlot) convert} a 357 * virtual slot to a frame slot index 358 */ 359 RegisterSaveLayout getMap(FrameMap frameMap); 360 361 } 362 363 /** 364 * A LIR operation that does nothing. If the operation records its position, it can be 365 * subsequently {@linkplain #replace(LIR, LIRInstruction) replaced}. 366 */ 367 public static final class NoOp extends LIRInstruction { 368 public static final LIRInstructionClass<NoOp> TYPE = LIRInstructionClass.create(NoOp.class); 369 370 /** 371 * The block in which this instruction is located. 372 */ 373 final AbstractBlockBase<?> block; 374 375 /** 376 * The block index of this instruction. 377 */ 378 final int index; 379 380 public NoOp(AbstractBlockBase<?> block, int index) { 381 super(TYPE); 382 this.block = block; 383 this.index = index; 384 } 385 386 public void replace(LIR lir, LIRInstruction replacement) { 387 List<LIRInstruction> instructions = lir.getLIRforBlock(block); 388 assert instructions.get(index).equals(this) : String.format("Replacing the wrong instruction: %s instead of %s", instructions.get(index), this); 389 instructions.set(index, replacement); 390 } 391 392 public void remove(LIR lir) { 393 List<LIRInstruction> instructions = lir.getLIRforBlock(block); 394 assert instructions.get(index).equals(this) : String.format("Removing the wrong instruction: %s instead of %s", instructions.get(index), this); 395 instructions.remove(index); 396 } 397 398 @Override 399 public void emitCode(CompilationResultBuilder crb) { 400 if (block != null) { 401 throw new GraalError(this + " should have been replaced"); 402 } 403 } 404 } 405 406 @Opcode("BLACKHOLE") 407 public static final class BlackholeOp extends LIRInstruction { 408 public static final LIRInstructionClass<BlackholeOp> TYPE = LIRInstructionClass.create(BlackholeOp.class); 409 410 @Use({REG, STACK, CONST}) private Value value; 411 412 public BlackholeOp(Value value) { 413 super(TYPE); 414 this.value = value; 415 } 416 417 @Override 418 public void emitCode(CompilationResultBuilder crb) { 419 // do nothing, just keep value alive until at least here 420 } 421 } 422 423 public static final class BindToRegisterOp extends LIRInstruction { 424 public static final LIRInstructionClass<BindToRegisterOp> TYPE = LIRInstructionClass.create(BindToRegisterOp.class); 425 426 @Use({REG}) private Value value; 427 428 public BindToRegisterOp(Value value) { 429 super(TYPE); 430 this.value = value; 431 } 432 433 @Override 434 public void emitCode(CompilationResultBuilder crb) { 435 // do nothing, just keep value alive until at least here 436 } 437 } 438 439 @Opcode("SPILLREGISTERS") 440 public static final class SpillRegistersOp extends LIRInstruction { 441 public static final LIRInstructionClass<SpillRegistersOp> TYPE = LIRInstructionClass.create(SpillRegistersOp.class); 442 443 public SpillRegistersOp() { 444 super(TYPE); 445 } 446 447 @Override 448 public boolean destroysCallerSavedRegisters() { 449 return true; 450 } 451 452 @Override 453 public void emitCode(CompilationResultBuilder crb) { 454 // do nothing, just keep value alive until at least here 455 } 456 } 457 458 public static final class StackMove extends LIRInstruction implements ValueMoveOp { 459 public static final LIRInstructionClass<StackMove> TYPE = LIRInstructionClass.create(StackMove.class); 460 461 @Def({STACK, HINT}) protected AllocatableValue result; 462 @Use({STACK}) protected AllocatableValue input; 463 464 public StackMove(AllocatableValue result, AllocatableValue input) { 465 super(TYPE); 466 this.result = result; 467 this.input = input; 468 } 469 470 @Override 471 public void emitCode(CompilationResultBuilder crb) { 472 throw new GraalError(this + " should have been removed"); 473 } 474 475 @Override 476 public AllocatableValue getInput() { 477 return input; 478 } 479 480 @Override 481 public AllocatableValue getResult() { 482 return result; 483 } 484 } 485 486 }