Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags
save = null;
preservedRegisters.clear();
} else {
op.visitEachUseKill(defConsumer);
op.visitEachTemp(defConsumer);
op.visitEachOutput(defConsumer);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ private static void processBlock(DiagnosticLIRGeneratorTool diagnosticLirGenTool
destroyedRegisters.remove(reg);
}
};
inst.visitEachUseKill(tempConsumer);
inst.visitEachTemp(tempConsumer);
inst.visitEachOutput(defConsumer);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ protected void verifyBlock(LIR lir, BasicBlock<?> block) {

protected void verifyInstruction(LIRInstruction inst) {
inst.visitEachInput(this::verifyOperands);
inst.visitEachUseKill(this::verifyOperands);
inst.visitEachOutput(this::verifyOperands);
inst.visitEachAlive(this::verifyOperands);
inst.visitEachTemp(this::verifyOperands);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import static jdk.graal.compiler.lir.LIRInstruction.OperandMode.ALIVE;
import static jdk.graal.compiler.lir.LIRInstruction.OperandMode.DEF;
import static jdk.graal.compiler.lir.LIRInstruction.OperandMode.TEMP;
import static jdk.graal.compiler.lir.LIRInstruction.OperandMode.USE_KILL;
import static jdk.graal.compiler.lir.LIRValueUtil.isVirtualStackSlot;
import static jdk.vm.ci.code.ValueUtil.isStackSlot;

Expand Down Expand Up @@ -95,6 +96,13 @@ public enum OperandMode {
*/
USE,

/**
* The value must have been defined before. It is read at the beginning of the instruction,
* and then killed by the instruction. A register assigned to it can also be assigned to a
* {@link #TEMP} or {@link #DEF} operand after the use.
*/
USE_KILL,

/**
* The value must have been defined before. It is alive before the instruction and
* throughout the instruction. A register assigned to it cannot be assigned to a
Expand Down Expand Up @@ -131,6 +139,13 @@ public enum OperandMode {
OperandFlag[] value() default OperandFlag.REG;
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface UseKill {

OperandFlag[] value() default OperandFlag.REG;
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Temp {
Expand Down Expand Up @@ -205,6 +220,7 @@ public enum OperandFlag {
static {
ALLOWED_FLAGS = new EnumMap<>(OperandMode.class);
ALLOWED_FLAGS.put(OperandMode.USE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED));
ALLOWED_FLAGS.put(USE_KILL, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, HINT));
ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED, OUTGOING));
ALLOWED_FLAGS.put(TEMP, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, HINT));
ALLOWED_FLAGS.put(DEF, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, HINT));
Expand Down Expand Up @@ -274,6 +290,10 @@ public final void forEachAlive(InstructionValueProcedure proc) {
instructionClass.forEachAlive(this, proc);
}

public final void forEachUseKill(InstructionValueProcedure proc) {
instructionClass.forEachUseKill(this, proc);
}

public final void forEachTemp(InstructionValueProcedure proc) {
instructionClass.forEachTemp(this, proc);
}
Expand All @@ -295,6 +315,10 @@ public final void forEachAlive(ValueProcedure proc) {
instructionClass.forEachAlive(this, proc);
}

public final void forEachUseKill(ValueProcedure proc) {
instructionClass.forEachUseKill(this, proc);
}

public final void forEachTemp(ValueProcedure proc) {
instructionClass.forEachTemp(this, proc);
}
Expand Down Expand Up @@ -325,6 +349,10 @@ public final void visitEachAlive(InstructionValueConsumer proc) {
instructionClass.visitEachAlive(this, proc);
}

public final void visitEachUseKill(InstructionValueConsumer proc) {
instructionClass.visitEachUseKill(this, proc);
}

public final void visitEachTemp(InstructionValueConsumer proc) {
instructionClass.visitEachTemp(this, proc);
}
Expand All @@ -346,6 +374,10 @@ public final void visitEachAlive(ValueConsumer proc) {
instructionClass.visitEachAlive(this, proc);
}

public final void visitEachUseKill(ValueConsumer proc) {
instructionClass.visitEachUseKill(this, proc);
}

public final void visitEachTemp(ValueConsumer proc) {
instructionClass.visitEachTemp(this, proc);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public static <T extends LIRInstruction> LIRInstructionClass<T> create(Class<T>
private static final Class<LIRFrameState> STATE_CLASS = LIRFrameState.class;

private final Values uses;
private final Values useKills;
private final Values alives;
private final Values temps;
private final Values defs;
Expand All @@ -74,6 +75,7 @@ public LIRInstructionClass(Class<T> clazz) {
ifs.scan(clazz, LIRInstruction.class);

uses = Values.create(ifs.valueAnnotations.get(LIRInstruction.Use.class));
useKills = Values.create(ifs.valueAnnotations.get(LIRInstruction.UseKill.class));
alives = Values.create(ifs.valueAnnotations.get(LIRInstruction.Alive.class));
temps = Values.create(ifs.valueAnnotations.get(LIRInstruction.Temp.class));
defs = Values.create(ifs.valueAnnotations.get(LIRInstruction.Def.class));
Expand Down Expand Up @@ -120,6 +122,7 @@ private static class LIRInstructionFieldsScanner extends LIRFieldsScanner {

LIRInstructionFieldsScanner() {
valueAnnotations.put(LIRInstruction.Use.class, new OperandModeAnnotation());
valueAnnotations.put(LIRInstruction.UseKill.class, new OperandModeAnnotation());
valueAnnotations.put(LIRInstruction.Alive.class, new OperandModeAnnotation());
valueAnnotations.put(LIRInstruction.Temp.class, new OperandModeAnnotation());
valueAnnotations.put(LIRInstruction.Def.class, new OperandModeAnnotation());
Expand All @@ -134,6 +137,8 @@ protected EnumSet<OperandFlag> getFlags(Field field) {
// from arrays to EnumSet manually.
if (field.isAnnotationPresent(LIRInstruction.Use.class)) {
result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Use.class).value()));
} else if (field.isAnnotationPresent(LIRInstruction.UseKill.class)) {
result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.UseKill.class).value()));
} else if (field.isAnnotationPresent(LIRInstruction.Alive.class)) {
result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Alive.class).value()));
} else if (field.isAnnotationPresent(LIRInstruction.Temp.class)) {
Expand Down Expand Up @@ -186,14 +191,16 @@ protected void scanField(Field field, long offset) {
@Override
public Fields[] getAllFields() {
assert values == null;
return new Fields[]{data, uses, alives, temps, defs, states};
return new Fields[]{data, uses, useKills, alives, temps, defs, states};
}

@Override
public String toString() {
StringBuilder str = new StringBuilder();
str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" use[");
uses.appendFields(str);
str.append("] useKill[");
useKills.appendFields(str);
str.append("] alive[");
alives.appendFields(str);
str.append("] temp[");
Expand All @@ -217,7 +224,7 @@ final String getOpcode(LIRInstruction obj) {
}

final boolean hasOperands() {
return uses.getCount() > 0 || alives.getCount() > 0 || temps.getCount() > 0 || defs.getCount() > 0;
return uses.getCount() > 0 || useKills.getCount() > 0 || alives.getCount() > 0 || temps.getCount() > 0 || defs.getCount() > 0;
}

final boolean hasState(LIRInstruction obj) {
Expand All @@ -237,6 +244,10 @@ final void forEachAlive(LIRInstruction obj, InstructionValueProcedure proc) {
forEach(obj, alives, OperandMode.ALIVE, proc);
}

final void forEachUseKill(LIRInstruction obj, InstructionValueProcedure proc) {
forEach(obj, useKills, OperandMode.USE_KILL, proc);
}

final void forEachTemp(LIRInstruction obj, InstructionValueProcedure proc) {
forEach(obj, temps, OperandMode.TEMP, proc);
}
Expand All @@ -253,6 +264,10 @@ final void visitEachAlive(LIRInstruction obj, InstructionValueConsumer proc) {
visitEach(obj, alives, OperandMode.ALIVE, proc);
}

final void visitEachUseKill(LIRInstruction obj, InstructionValueConsumer proc) {
visitEach(obj, useKills, OperandMode.USE_KILL, proc);
}

final void visitEachTemp(LIRInstruction obj, InstructionValueConsumer proc) {
visitEach(obj, temps, OperandMode.TEMP, proc);
}
Expand Down Expand Up @@ -289,15 +304,20 @@ final void forEachState(LIRInstruction obj, InstructionStateProcedure proc) {
}

final Value forEachRegisterHint(LIRInstruction obj, OperandMode mode, InstructionValueProcedure proc) {
Values hints;
if (mode == OperandMode.USE) {
hints = defs;
if (mode == OperandMode.USE || mode == OperandMode.USE_KILL) {
return forEachRegisterHint(obj, defs, proc);
} else if (mode == OperandMode.DEF) {
hints = uses;
Value result = forEachRegisterHint(obj, uses, proc);
if (result != null) {
return result;
}
return forEachRegisterHint(obj, useKills, proc);
} else {
return null;
}
}

private static Value forEachRegisterHint(LIRInstruction obj, Values hints, InstructionValueProcedure proc) {
for (int i = 0; i < hints.getCount(); i++) {
if (i < hints.getDirectCount()) {
Value hintValue = hints.getValue(obj, i);
Expand All @@ -323,7 +343,7 @@ String toString(LIRInstruction obj) {

appendValues(result, obj, "", " = ", "(", ")", true, new String[]{""}, defs);
result.append(String.valueOf(getOpcode(obj)).toUpperCase(Locale.ROOT));
appendValues(result, obj, " ", "", "(", ")", false, new String[]{"", "~"}, uses, alives);
appendValues(result, obj, " ", "", "(", ")", false, new String[]{"", "!", "~"}, uses, useKills, alives);
appendValues(result, obj, " ", "", "{", "}", false, new String[]{""}, temps);

for (int i = 0; i < data.getCount(); i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> fla

OutputValueConsumer outputValueConsumer = new OutputValueConsumer(valueNum);

op.visitEachUseKill(outputValueConsumer);
op.visitEachTemp(outputValueConsumer);
/*
* Semantically the output values are written _after_ the temp values
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ protected void verifyInstruction(LIRInstruction inst) {
inst.visitEachInput(this::verifyOperands);
inst.visitEachOutput(this::verifyOperands);
inst.visitEachAlive(this::verifyOperands);
inst.visitEachUseKill(this::verifyOperands);
inst.visitEachTemp(this::verifyOperands);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.graal.compiler.lir.alloc;

import java.util.ArrayList;

import jdk.graal.compiler.core.common.cfg.BasicBlock;
import jdk.graal.compiler.lir.LIR;
import jdk.graal.compiler.lir.LIRInsertionBuffer;
import jdk.graal.compiler.lir.LIRInstruction;
import jdk.graal.compiler.lir.LIRValueUtil;
import jdk.graal.compiler.lir.Variable;
import jdk.graal.compiler.lir.gen.LIRGenerationResult;
import jdk.graal.compiler.lir.gen.LIRGeneratorTool;
import jdk.graal.compiler.lir.phases.PreAllocationOptimizationPhase;
import jdk.vm.ci.code.TargetDescription;

/**
* Lowers {@code @UseKill} operands to short-lived variables by inserting moves immediately before
* the consuming instructions.
*/
public final class UseKillMoveInjectionPhase extends PreAllocationOptimizationPhase {

@Override
protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PreAllocationOptimizationContext context) {
new Optimization(lirGenRes, context.lirGen).apply();
}

private static final class Optimization {
private final LIRGenerationResult lirGenRes;
private final LIR lir;
private final LIRGeneratorTool lirGen;

private Optimization(LIRGenerationResult lirGenRes, LIRGeneratorTool lirGen) {
this.lirGenRes = lirGenRes;
this.lir = lirGenRes.getLIR();
this.lirGen = lirGen;
}

private void apply() {
for (BasicBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
rewriteBlock(block);
}
}

private void rewriteBlock(BasicBlock<?> block) {
ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(block);
LIRInsertionBuffer buffer = new LIRInsertionBuffer();

for (int i = 0; i < instructions.size(); i++) {
final int insertionIndex = i;
LIRInstruction op = instructions.get(i);
op.forEachUseKill((instruction, value, mode, flags) -> {
if (!LIRValueUtil.isVariable(value)) {
return value;
}

if (!buffer.initialized()) {
buffer.init(instructions);
}

Variable movedValue = lirGen.newVariable(value.getValueKind());
LIRInstruction move = lirGen.getSpillMoveFactory().createMove(movedValue, value);
move.setComment(lirGenRes, "UseKillMoveInjection");
buffer.append(insertionIndex, move);
return movedValue;
});
}

if (buffer.initialized()) {
buffer.finish();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -192,14 +192,16 @@ public Value doValue(LIRInstruction instruction, Value value, LIRInstruction.Ope
if (LIRValueUtil.isVariable(value)) {
Value location = colorLirOperand(instruction, LIRValueUtil.asVariable(value), mode);
if (LIRValueUtil.isCast(value)) {
GraalError.guarantee(mode == LIRInstruction.OperandMode.USE || mode == LIRInstruction.OperandMode.ALIVE, "Invalid application of CastValue");
GraalError.guarantee(mode == LIRInstruction.OperandMode.USE || mode == LIRInstruction.OperandMode.USE_KILL || mode == LIRInstruction.OperandMode.ALIVE,
"Invalid application of CastValue");
// return the same location, but with the cast's kind.
CastValue cast = (CastValue) value;
return LIRValueUtil.changeValueKind(location, cast.getValueKind(), true);
}
return location;
} else if (LIRValueUtil.isCast(value)) {
GraalError.guarantee(mode == LIRInstruction.OperandMode.USE || mode == LIRInstruction.OperandMode.ALIVE, "Invalid application of CastValue");
GraalError.guarantee(mode == LIRInstruction.OperandMode.USE || mode == LIRInstruction.OperandMode.USE_KILL || mode == LIRInstruction.OperandMode.ALIVE,
"Invalid application of CastValue");
// strip CastValue: return underlying value, but with the cast's kind.
CastValue cast = (CastValue) value;
return LIRValueUtil.changeValueKind(cast.underlyingValue(), cast.getValueKind(), false);
Expand Down Expand Up @@ -252,6 +254,7 @@ protected LIRInstruction assignLocations(LIRInstruction inputOp) {

op.forEachInput(assignProc);
op.forEachAlive(assignProc);
op.forEachUseKill(assignProc);
op.forEachTemp(assignProc);
op.forEachOutput(assignProc);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,12 +253,14 @@ void computeLocalLiveSets() {

try (Indent indent2 = debug.logAndIndent("handle op %d: %s", op.id(), op)) {
op.visitEachInput(useConsumer);
op.visitEachUseKill(useConsumer);
op.visitEachAlive(useConsumer);
/*
* Add uses of live locals from interpreter's point of view for proper
* debug information generation.
*/
op.visitEachState(stateConsumer);
op.visitEachUseKill(defConsumer);
op.visitEachTemp(defConsumer);
op.visitEachOutput(defConsumer);
}
Expand Down Expand Up @@ -895,9 +897,11 @@ protected void buildIntervals() {
}

op.visitEachOutput(outputConsumer);
op.visitEachUseKill(tempConsumer);
op.visitEachTemp(tempConsumer);
op.visitEachAlive(aliveConsumer);
op.visitEachInput(inputConsumer);
op.visitEachUseKill(inputConsumer);

/*
* Add uses of live locals from interpreter's point of view for proper
Expand Down
Loading