1 /*
   2  * Copyright (c) 2011, 2019, 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 jdk.vm.ci.code.ValueUtil.asStackSlot;
  28 import static jdk.vm.ci.code.ValueUtil.isStackSlot;
  29 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST;
  30 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
  31 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.OUTGOING;
  32 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
  33 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
  34 
  35 import java.util.ArrayList;
  36 import java.util.Arrays;
  37 import java.util.EnumSet;
  38 
  39 import jdk.internal.vm.compiler.collections.EconomicSet;
  40 import jdk.internal.vm.compiler.collections.Equivalence;
  41 import org.graalvm.compiler.asm.Label;
  42 import org.graalvm.compiler.core.common.GraalOptions;
  43 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
  44 import org.graalvm.compiler.debug.GraalError;
  45 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
  46 import org.graalvm.compiler.lir.framemap.FrameMap;
  47 
  48 import jdk.vm.ci.code.Register;
  49 import jdk.vm.ci.code.RegisterSaveLayout;
  50 import jdk.vm.ci.code.StackSlot;
  51 import jdk.vm.ci.meta.AllocatableValue;
  52 import jdk.vm.ci.meta.Constant;
  53 import jdk.vm.ci.meta.Value;
  54 
  55 /**
  56  * A collection of machine-independent LIR operations, as well as interfaces to be implemented for
  57  * specific kinds or LIR operations.
  58  */
  59 public class StandardOp {
  60 
  61     /**
  62      * A block delimiter. Every well formed block must contain exactly one such operation and it
  63      * must be the last operation in the block.
  64      */
  65     public interface BlockEndOp {
  66     }
  67 
  68     public interface NullCheck {
  69         Value getCheckedValue();
  70 
  71         LIRFrameState getState();
  72     }
  73 
  74     public interface ImplicitNullCheck {
  75         boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit);
  76     }
  77 
  78     public interface LabelHoldingOp {
  79         Label getLabel();
  80     }
  81 
  82     /**
  83      * LIR operation that defines the position of a label.
  84      */
  85     public static final class LabelOp extends LIRInstruction implements LabelHoldingOp {
  86         public static final LIRInstructionClass<LabelOp> TYPE = LIRInstructionClass.create(LabelOp.class);
  87         public static final EnumSet<OperandFlag> incomingFlags = EnumSet.of(REG, STACK);
  88 
  89         /**
  90          * In the LIR, every register and variable must be defined before it is used. For method
  91          * parameters that are passed in fixed registers, exception objects passed to the exception
  92          * handler in a fixed register, or any other use of a fixed register not defined in this
  93          * method, an artificial definition is necessary. To avoid spill moves to be inserted
  94          * between the label at the beginning of a block an an actual definition in the second
  95          * instruction of a block, the registers are defined here in the label.
  96          */
  97         @Def({REG, STACK}) private Value[] incomingValues;
  98         private final Label label;
  99         private final boolean align;
 100         private int numbPhis;
 101 
 102         public LabelOp(Label label, boolean align) {
 103             super(TYPE);
 104             this.label = label;
 105             this.align = align;
 106             this.incomingValues = Value.NO_VALUES;
 107             this.numbPhis = 0;
 108         }
 109 
 110         public void setPhiValues(Value[] values) {
 111             setIncomingValues(values);
 112             setNumberOfPhis(values.length);
 113         }
 114 
 115         private void setNumberOfPhis(int numPhis) {
 116             assert numbPhis == 0;
 117             numbPhis = numPhis;
 118         }
 119 
 120         public int getPhiSize() {
 121             return numbPhis;
 122         }
 123 
 124         public void setIncomingValues(Value[] values) {
 125             assert this.incomingValues.length == 0;
 126             assert values != null;
 127             this.incomingValues = values;
 128         }
 129 
 130         public int getIncomingSize() {
 131             return incomingValues.length;
 132         }
 133 
 134         public Value getIncomingValue(int idx) {
 135             assert checkRange(idx);
 136             return incomingValues[idx];
 137         }
 138 
 139         public void clearIncomingValues() {
 140             incomingValues = Value.NO_VALUES;
 141         }
 142 
 143         public void addIncomingValues(Value[] values) {
 144             if (incomingValues.length == 0) {
 145                 setIncomingValues(values);
 146                 return;
 147             }
 148             int t = incomingValues.length + values.length;
 149             Value[] newArray = new Value[t];
 150             System.arraycopy(incomingValues, 0, newArray, 0, incomingValues.length);
 151             System.arraycopy(values, 0, newArray, incomingValues.length, values.length);
 152             incomingValues = newArray;
 153         }
 154 
 155         private boolean checkRange(int idx) {
 156             return idx < incomingValues.length;
 157         }
 158 
 159         @Override
 160         public void emitCode(CompilationResultBuilder crb) {
 161             if (align) {
 162                 crb.asm.align(GraalOptions.LoopHeaderAlignment.getValue(crb.getOptions()));
 163             }
 164             crb.asm.bind(label);
 165         }
 166 
 167         @Override
 168         public Label getLabel() {
 169             return label;
 170         }
 171 
 172         /**
 173          * @return true if this label acts as a PhiIn.
 174          */
 175         public boolean isPhiIn() {
 176             return getPhiSize() > 0;
 177         }
 178 
 179         public void forEachIncomingValue(InstructionValueProcedure proc) {
 180             for (int i = 0; i < incomingValues.length; i++) {
 181                 incomingValues[i] = proc.doValue(this, incomingValues[i], OperandMode.DEF, incomingFlags);
 182             }
 183         }
 184     }
 185 
 186     /**
 187      * LIR operation that is an unconditional jump to a {@link #destination()}.
 188      */
 189     public static class JumpOp extends LIRInstruction implements BlockEndOp {
 190         public static final LIRInstructionClass<JumpOp> TYPE = LIRInstructionClass.create(JumpOp.class);
 191         public static final EnumSet<OperandFlag> outgoingFlags = EnumSet.of(REG, STACK, CONST, OUTGOING);
 192 
 193         @Alive({REG, STACK, CONST, OUTGOING}) private Value[] outgoingValues;
 194 
 195         private final LabelRef destination;
 196 
 197         public JumpOp(LabelRef destination) {
 198             this(TYPE, destination);
 199         }
 200 
 201         protected JumpOp(LIRInstructionClass<? extends JumpOp> c, LabelRef destination) {
 202             super(c);
 203             this.destination = destination;
 204             this.outgoingValues = Value.NO_VALUES;
 205         }
 206 
 207         @Override
 208         public void emitCode(CompilationResultBuilder crb) {
 209             if (!crb.isSuccessorEdge(destination)) {
 210                 crb.asm.jmp(destination.label());
 211             }
 212         }
 213 
 214         public LabelRef destination() {
 215             return destination;
 216         }
 217 
 218         public void setPhiValues(Value[] values) {
 219             assert this.outgoingValues.length == 0;
 220             assert values != null;
 221             this.outgoingValues = values;
 222         }
 223 
 224         public int getPhiSize() {
 225             return outgoingValues.length;
 226         }
 227 
 228         public Value getOutgoingValue(int idx) {
 229             assert checkRange(idx);
 230             return outgoingValues[idx];
 231         }
 232 
 233         public void clearOutgoingValues() {
 234             outgoingValues = Value.NO_VALUES;
 235         }
 236 
 237         private boolean checkRange(int idx) {
 238             return idx < outgoingValues.length;
 239         }
 240     }
 241 
 242     /**
 243      * Marker interface for a LIR operation that is a conditional jump.
 244      */
 245     public interface BranchOp extends BlockEndOp {
 246     }
 247 
 248     /**
 249      * Marker interface for a LIR operation that moves a value to {@link #getResult()}.
 250      */
 251     public interface MoveOp {
 252 
 253         AllocatableValue getResult();
 254 
 255         // Checkstyle: stop
 256         static MoveOp asMoveOp(LIRInstruction op) {
 257             return (MoveOp) op;
 258         }
 259         // Checkstyle: resume
 260 
 261         static boolean isMoveOp(LIRInstruction op) {
 262             return op.isMoveOp();
 263         }
 264     }
 265 
 266     /**
 267      * Marker interface for a LIR operation that moves some non-constant value to another location.
 268      */
 269     public interface ValueMoveOp extends MoveOp {
 270 
 271         AllocatableValue getInput();
 272 
 273         // Checkstyle: stop
 274         static ValueMoveOp asValueMoveOp(LIRInstruction op) {
 275             return (ValueMoveOp) op;
 276         }
 277         // Checkstyle: resume
 278 
 279         static boolean isValueMoveOp(LIRInstruction op) {
 280             return op.isValueMoveOp();
 281         }
 282     }
 283 
 284     /**
 285      * Marker interface for a LIR operation that loads a {@link #getConstant()}.
 286      */
 287     public interface LoadConstantOp extends MoveOp {
 288 
 289         Constant getConstant();
 290 
 291         // Checkstyle: stop
 292         static LoadConstantOp asLoadConstantOp(LIRInstruction op) {
 293             return (LoadConstantOp) op;
 294         }
 295         // Checkstyle: resume
 296 
 297         static boolean isLoadConstantOp(LIRInstruction op) {
 298             return op.isLoadConstantOp();
 299         }
 300     }
 301 
 302     /**
 303      * An operation that saves registers to the stack. The set of saved registers can be
 304      * {@linkplain #remove(EconomicSet) pruned} and a mapping from registers to the frame slots in
 305      * which they are saved can be {@linkplain #getMap(FrameMap) retrieved}.
 306      */
 307     public abstract static class SaveRegistersOp extends LIRInstruction {
 308         public static final LIRInstructionClass<SaveRegistersOp> TYPE = LIRInstructionClass.create(SaveRegistersOp.class);
 309 
 310         /**
 311          * The registers (potentially) saved by this operation.
 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         }
 332 
 333         /**
 334          * Prunes {@code doNotSave} from the registers saved by this operation.
 335          *
 336          * @param doNotSave registers that should not be saved by this operation
 337          * @return the number of registers pruned
 338          */
 339         public int remove(EconomicSet<Register> doNotSave) {
 340             return prune(doNotSave, savedRegisters);
 341         }
 342 
 343         /**
 344          * Gets a map from the saved registers saved by this operation to the frame slots in which
 345          * they are saved.
 346          *
 347          * @param frameMap used to {@linkplain FrameMap#offsetForStackSlot(StackSlot) convert} a
 348          *            virtual slot to a frame slot index
 349          */
 350 
 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 {
 433     }
 434 
 435     /**
 436      * A LIR operation that does nothing. If the operation records its position, it can be
 437      * subsequently {@linkplain #replace(LIR, LIRInstruction) replaced}.
 438      */
 439     public static final class NoOp extends LIRInstruction {
 440         public static final LIRInstructionClass<NoOp> TYPE = LIRInstructionClass.create(NoOp.class);
 441 
 442         /**
 443          * The block in which this instruction is located.
 444          */
 445         final AbstractBlockBase<?> block;
 446 
 447         /**
 448          * The block index of this instruction.
 449          */
 450         final int index;
 451 
 452         public NoOp(AbstractBlockBase<?> block, int index) {
 453             super(TYPE);
 454             this.block = block;
 455             this.index = index;
 456         }
 457 
 458         public void replace(LIR lir, LIRInstruction replacement) {
 459             ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(block);
 460             assert instructions.get(index).equals(this) : String.format("Replacing the wrong instruction: %s instead of %s", instructions.get(index), this);
 461             instructions.set(index, replacement);
 462         }
 463 
 464         public void remove(LIR lir) {
 465             ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(block);
 466             assert instructions.get(index).equals(this) : String.format("Removing the wrong instruction: %s instead of %s", instructions.get(index), this);
 467             instructions.remove(index);
 468         }
 469 
 470         @Override
 471         public void emitCode(CompilationResultBuilder crb) {
 472             if (block != null) {
 473                 throw new GraalError(this + " should have been replaced");
 474             }
 475         }
 476     }
 477 
 478     @Opcode("BLACKHOLE")
 479     public static final class BlackholeOp extends LIRInstruction {
 480         public static final LIRInstructionClass<BlackholeOp> TYPE = LIRInstructionClass.create(BlackholeOp.class);
 481 
 482         @Use({REG, STACK, CONST}) private Value value;
 483 
 484         public BlackholeOp(Value value) {
 485             super(TYPE);
 486             this.value = value;
 487         }
 488 
 489         @Override
 490         public void emitCode(CompilationResultBuilder crb) {
 491             // do nothing, just keep value alive until at least here
 492         }
 493     }
 494 
 495     public static final class BindToRegisterOp extends LIRInstruction {
 496         public static final LIRInstructionClass<BindToRegisterOp> TYPE = LIRInstructionClass.create(BindToRegisterOp.class);
 497 
 498         @Use({REG}) private Value value;
 499 
 500         public BindToRegisterOp(Value value) {
 501             super(TYPE);
 502             this.value = value;
 503         }
 504 
 505         @Override
 506         public void emitCode(CompilationResultBuilder crb) {
 507             // do nothing, just keep value alive until at least here
 508         }
 509     }
 510 
 511     @Opcode("SPILLREGISTERS")
 512     public static final class SpillRegistersOp extends LIRInstruction {
 513         public static final LIRInstructionClass<SpillRegistersOp> TYPE = LIRInstructionClass.create(SpillRegistersOp.class);
 514 
 515         public SpillRegistersOp() {
 516             super(TYPE);
 517         }
 518 
 519         @Override
 520         public boolean destroysCallerSavedRegisters() {
 521             return true;
 522         }
 523 
 524         @Override
 525         public void emitCode(CompilationResultBuilder crb) {
 526             // do nothing, just keep value alive until at least here
 527         }
 528     }
 529 
 530     public static final class StackMove extends LIRInstruction implements ValueMoveOp {
 531         public static final LIRInstructionClass<StackMove> TYPE = LIRInstructionClass.create(StackMove.class);
 532 
 533         @Def({STACK, HINT}) protected AllocatableValue result;
 534         @Use({STACK}) protected AllocatableValue input;
 535 
 536         public StackMove(AllocatableValue result, AllocatableValue input) {
 537             super(TYPE);
 538             this.result = result;
 539             this.input = input;
 540         }
 541 
 542         @Override
 543         public void emitCode(CompilationResultBuilder crb) {
 544             throw new GraalError(this + " should have been removed");
 545         }
 546 
 547         @Override
 548         public AllocatableValue getInput() {
 549             return input;
 550         }
 551 
 552         @Override
 553         public AllocatableValue getResult() {
 554             return result;
 555         }
 556     }
 557 
 558 }