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