--- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ControlFlow.java 2019-03-12 08:09:26.179512169 +0100 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ControlFlow.java 2019-03-12 08:09:25.831509910 +0100 @@ -31,6 +31,7 @@ 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; @@ -59,53 +60,21 @@ 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 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 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) { /* @@ -115,18 +84,104 @@ * 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 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 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 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")