< 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 >