< prev index next >
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ControlFlow.java
Print this page
@@ -29,10 +29,11 @@
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
import java.util.function.Function;
+import jdk.vm.ci.meta.AllocatableValue;
import org.graalvm.compiler.asm.Label;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag;
import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ExtendType;
@@ -57,78 +58,132 @@
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.Value;
public class AArch64ControlFlow {
- /**
- * Compares integer register to 0 and branches if condition is true. Condition may only be equal
- * or non-equal.
- */
- // TODO (das) where do we need this?
- // public static class CompareAndBranchOp extends AArch64LIRInstruction implements
- // StandardOp.BranchOp {
- // private final ConditionFlag condition;
- // private final LabelRef destination;
- // @Use({REG}) private Value x;
- //
- // public CompareAndBranchOp(Condition condition, LabelRef destination, Value x) {
- // assert condition == Condition.EQ || condition == Condition.NE;
- // assert ARMv8.isGpKind(x.getKind());
- // this.condition = condition == Condition.EQ ? ConditionFlag.EQ : ConditionFlag.NE;
- // this.destination = destination;
- // this.x = x;
- // }
- //
- // @Override
- // public void emitCode(CompilationResultBuilder crb, ARMv8MacroAssembler masm) {
- // int size = ARMv8.bitsize(x.getKind());
- // if (condition == ConditionFlag.EQ) {
- // masm.cbz(size, asRegister(x), destination.label());
- // } else {
- // masm.cbnz(size, asRegister(x), destination.label());
- // }
- // }
- // }
-
- public static class BranchOp extends AArch64BlockEndOp implements StandardOp.BranchOp {
- public static final LIRInstructionClass<BranchOp> TYPE = LIRInstructionClass.create(BranchOp.class);
-
- private final AArch64Assembler.ConditionFlag condition;
+ public abstract static class AbstractBranchOp extends AArch64BlockEndOp implements StandardOp.BranchOp {
private final LabelRef trueDestination;
private final LabelRef falseDestination;
private final double trueDestinationProbability;
- public BranchOp(AArch64Assembler.ConditionFlag condition, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
- super(TYPE);
- this.condition = condition;
+ private AbstractBranchOp(LIRInstructionClass<? extends AbstractBranchOp> c, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
+ super(c);
this.trueDestination = trueDestination;
this.falseDestination = falseDestination;
this.trueDestinationProbability = trueDestinationProbability;
}
+ protected abstract void emitBranch(CompilationResultBuilder crb, AArch64MacroAssembler masm, LabelRef target, boolean negate);
+
@Override
public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
/*
* Explanation: Depending on what the successor edge is, we can use the fall-through to
* optimize the generated code. If neither is a successor edge, use the branch
* probability to try to take the conditional jump as often as possible to avoid
* executing two instructions instead of one.
*/
if (crb.isSuccessorEdge(trueDestination)) {
- masm.branchConditionally(condition.negate(), falseDestination.label());
+ emitBranch(crb, masm, falseDestination, true);
} else if (crb.isSuccessorEdge(falseDestination)) {
- masm.branchConditionally(condition, trueDestination.label());
+ emitBranch(crb, masm, trueDestination, false);
} else if (trueDestinationProbability < 0.5) {
- masm.branchConditionally(condition.negate(), falseDestination.label());
+ emitBranch(crb, masm, falseDestination, true);
masm.jmp(trueDestination.label());
} else {
- masm.branchConditionally(condition, trueDestination.label());
+ emitBranch(crb, masm, trueDestination, false);
masm.jmp(falseDestination.label());
}
}
+ }
+
+ public static class BranchOp extends AbstractBranchOp implements StandardOp.BranchOp {
+ public static final LIRInstructionClass<BranchOp> TYPE = LIRInstructionClass.create(BranchOp.class);
+
+ private final AArch64Assembler.ConditionFlag condition;
+
+ public BranchOp(AArch64Assembler.ConditionFlag condition, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
+ super(TYPE, trueDestination, falseDestination, trueDestinationProbability);
+ this.condition = condition;
+ }
+
+ @Override
+ protected void emitBranch(CompilationResultBuilder crb, AArch64MacroAssembler masm, LabelRef target, boolean negate) {
+ AArch64Assembler.ConditionFlag finalCond = negate ? condition.negate() : condition;
+ masm.branchConditionally(finalCond, target.label());
+ }
+ }
+
+ public static class CompareBranchZeroOp extends AbstractBranchOp implements StandardOp.BranchOp {
+ public static final LIRInstructionClass<CompareBranchZeroOp> TYPE = LIRInstructionClass.create(CompareBranchZeroOp.class);
+
+ @Use(REG) private AllocatableValue value;
+
+ public CompareBranchZeroOp(AllocatableValue value, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
+ super(TYPE, trueDestination, falseDestination, trueDestinationProbability);
+ this.value = value;
+ }
+ @Override
+ protected void emitBranch(CompilationResultBuilder crb, AArch64MacroAssembler masm, LabelRef target, boolean negate) {
+ AArch64Kind kind = (AArch64Kind) this.value.getPlatformKind();
+ assert kind.isInteger();
+ int size = kind.getSizeInBytes() * Byte.SIZE;
+
+ if (negate) {
+ masm.cbnz(size, asRegister(this.value), target.label());
+ } else {
+ masm.cbz(size, asRegister(this.value), target.label());
+ }
+ }
+ }
+
+ public static class BitTestAndBranchOp extends AbstractBranchOp implements StandardOp.BranchOp {
+ public static final LIRInstructionClass<BitTestAndBranchOp> TYPE = LIRInstructionClass.create(BitTestAndBranchOp.class);
+
+ @Use protected AllocatableValue value;
+ private final int index;
+
+ public BitTestAndBranchOp(LabelRef trueDestination, LabelRef falseDestination, AllocatableValue value, double trueDestinationProbability, int index) {
+ super(TYPE, trueDestination, falseDestination, trueDestinationProbability);
+ this.value = value;
+ this.index = index;
+ }
+
+ @Override
+ protected void emitBranch(CompilationResultBuilder crb, AArch64MacroAssembler masm, LabelRef target, boolean negate) {
+ ConditionFlag cond = negate ? ConditionFlag.NE : ConditionFlag.EQ;
+ Label label = target.label();
+ boolean isFarBranch;
+
+ if (label.isBound()) {
+ isFarBranch = NumUtil.isSignedNbit(18, masm.position() - label.position());
+ } else {
+ // Max range of tbz is +-2^13 instructions. We estimate that each LIR instruction
+ // emits 2 AArch64 instructions on average. Thus we test for maximum 2^12 LIR
+ // instruction offset.
+ int maxLIRDistance = (1 << 12);
+ isFarBranch = !crb.labelWithinRange(this, label, maxLIRDistance);
+ }
+
+ if (isFarBranch) {
+ cond = cond.negate();
+ label = new Label();
+ }
+
+ if (cond == ConditionFlag.EQ) {
+ masm.tbz(asRegister(value), index, label);
+ } else {
+ masm.tbnz(asRegister(value), index, label);
+ }
+
+ if (isFarBranch) {
+ masm.jmp(target.label());
+ masm.bind(label);
+ }
+ }
}
@Opcode("CMOVE")
public static class CondMoveOp extends AArch64LIRInstruction {
public static final LIRInstructionClass<CondMoveOp> TYPE = LIRInstructionClass.create(CondMoveOp.class);
< prev index next >