< 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,38 **** --- 29,39 ---- 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,134 **** 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; 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; this.trueDestination = trueDestination; this.falseDestination = falseDestination; this.trueDestinationProbability = trueDestinationProbability; } @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()); } else if (crb.isSuccessorEdge(falseDestination)) { ! masm.branchConditionally(condition, trueDestination.label()); } else if (trueDestinationProbability < 0.5) { ! masm.branchConditionally(condition.negate(), falseDestination.label()); masm.jmp(trueDestination.label()); } else { ! masm.branchConditionally(condition, trueDestination.label()); masm.jmp(falseDestination.label()); } } } @Opcode("CMOVE") public static class CondMoveOp extends AArch64LIRInstruction { public static final LIRInstructionClass<CondMoveOp> TYPE = LIRInstructionClass.create(CondMoveOp.class); --- 58,189 ---- import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.Value; public class AArch64ControlFlow { ! public abstract static class AbstractBranchOp extends AArch64BlockEndOp implements StandardOp.BranchOp { private final LabelRef trueDestination; private final LabelRef falseDestination; private final double trueDestinationProbability; ! 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)) { ! emitBranch(crb, masm, falseDestination, true); } else if (crb.isSuccessorEdge(falseDestination)) { ! emitBranch(crb, masm, trueDestination, false); } else if (trueDestinationProbability < 0.5) { ! emitBranch(crb, masm, falseDestination, true); masm.jmp(trueDestination.label()); } else { ! 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 >