1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 package org.graalvm.compiler.core.aarch64.test;
  26 
  27 import static org.junit.Assume.assumeTrue;
  28 
  29 import java.util.function.Predicate;
  30 
  31 import org.graalvm.compiler.api.directives.GraalDirectives;
  32 import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
  33 import org.graalvm.compiler.lir.LIR;
  34 import org.graalvm.compiler.lir.LIRInstruction;
  35 import org.graalvm.compiler.lir.LIRInstructionClass;
  36 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow;
  37 import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction;
  38 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
  39 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
  40 import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
  41 import org.graalvm.compiler.lir.jtt.LIRTest;
  42 import org.graalvm.compiler.lir.jtt.LIRTestSpecification;
  43 import org.graalvm.compiler.lir.phases.LIRPhase;
  44 import org.graalvm.compiler.lir.phases.LIRSuites;
  45 import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
  46 import org.graalvm.compiler.options.OptionValues;
  47 import org.junit.Assert;
  48 import org.junit.Before;
  49 import org.junit.Test;
  50 
  51 import jdk.vm.ci.aarch64.AArch64;
  52 import jdk.vm.ci.code.TargetDescription;
  53 import jdk.vm.ci.meta.Value;
  54 
  55 public class AArch64TestBitAndBranchTest extends LIRTest {
  56     private static final Predicate<LIRInstruction> checkForBitTestAndBranchOp = op -> (op instanceof AArch64ControlFlow.BitTestAndBranchOp);
  57     private LIR lir;
  58 
  59     @Before
  60     public void checkAArch64() {
  61         assumeTrue("skipping AArch64 specific test", getTarget().arch instanceof AArch64);
  62     }
  63 
  64     public static long testBit42Snippet(long a, long b, long c) {
  65         if ((a & (1 << 42)) == 0) {
  66             return b;
  67         } else {
  68             return c;
  69         }
  70     }
  71 
  72     @Test
  73     public void testBit42() {
  74         test("testBit42Snippet", 1L << 42L, Long.MAX_VALUE, Long.MIN_VALUE);
  75         test("testBit42Snippet", ~(1L << 42L), Long.MAX_VALUE, Long.MIN_VALUE);
  76         checkLIR("testBit42Snippet", checkForBitTestAndBranchOp, 1);
  77     }
  78 
  79     private static final LargeOpSpec largeOpSingleNop = new LargeOpSpec((1 << 14 - 2), 2);
  80 
  81     /**
  82      * Tests the graceful case, where the estimation for
  83      * {@link CompilationResultBuilder#labelWithinRange(LIRInstruction, org.graalvm.compiler.asm.Label, int)}
  84      * holds.
  85      */
  86     public static int testBitTestAndBranchSingleSnippet(int a) {
  87         int res;
  88         if (a % 2 == 0) {
  89             res = fillOps(largeOpSingleNop, 1);
  90         } else {
  91             res = fillOps(largeOpSingleNop, 2);
  92         }
  93         return GraalDirectives.opaque(res);
  94     }
  95 
  96     @Test
  97     public void testBitTestAndBranchSingle() {
  98         runTest("testBitTestAndBranchSingleSnippet", 1);
  99         checkLIR("testBitTestAndBranchSingleSnippet", checkForBitTestAndBranchOp, 1);
 100     }
 101 
 102     private static final LargeOpSpec largeOpFourNop = new LargeOpSpec((1 << 14 - 2), 8);
 103 
 104     /**
 105      * Tests the case, where the estimation for
 106      * {@link CompilationResultBuilder#labelWithinRange(LIRInstruction, org.graalvm.compiler.asm.Label, int)}
 107      * does not hold and the code generation must be redone with large branches.
 108      */
 109     public static int testBitTestAndBranchFourSnippet(int a) {
 110         int res;
 111         if (a % 2 == 0) {
 112             res = fillOps(largeOpFourNop, 1);
 113         } else {
 114             res = fillOps(largeOpFourNop, 2);
 115         }
 116         return GraalDirectives.opaque(res);
 117     }
 118 
 119     @Test
 120     public void testBitTestAndBranchFour() {
 121         runTest("testBitTestAndBranchFourSnippet", 1);
 122         checkLIR("testBitTestAndBranchFourSnippet", checkForBitTestAndBranchOp, 1);
 123     }
 124 
 125     private static class LargeOpSpec extends LIRTestSpecification {
 126         private final int n;
 127         private final int nopCount;
 128 
 129         LargeOpSpec(int n, int nopCount) {
 130             super();
 131             this.n = n;
 132             this.nopCount = nopCount;
 133         }
 134 
 135         @Override
 136         public void generate(LIRGeneratorTool gen, Value a) {
 137             for (int i = 0; i < n; i++) {
 138                 gen.append(new NoOp(nopCount));
 139             }
 140             setResult(a);
 141         }
 142     }
 143 
 144     public static class NoOp extends AArch64LIRInstruction {
 145         private static final LIRInstructionClass<NoOp> TYPE = LIRInstructionClass.create(NoOp.class);
 146         private final int nopCount;
 147 
 148         public NoOp(int nopCount) {
 149             super(TYPE);
 150             this.nopCount = nopCount;
 151         }
 152 
 153         @Override
 154         protected void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
 155             for (int i = 0; i < nopCount; i++) {
 156                 masm.nop();
 157             }
 158         }
 159     }
 160 
 161     @LIRIntrinsic
 162     public static int fillOps(@SuppressWarnings("unused") LargeOpSpec s, int a) {
 163         return a;
 164     }
 165 
 166     @Override
 167     protected LIRSuites createLIRSuites(OptionValues options) {
 168         LIRSuites suites = super.createLIRSuites(options);
 169         suites.getPreAllocationOptimizationStage().appendPhase(new CheckPhase());
 170         return suites;
 171     }
 172 
 173     public class CheckPhase extends LIRPhase<PreAllocationOptimizationContext> {
 174         @Override
 175         protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PreAllocationOptimizationContext context) {
 176             lir = lirGenRes.getLIR();
 177         }
 178     }
 179 
 180     protected void checkLIR(String methodName, Predicate<LIRInstruction> predicate, int expected) {
 181         compile(getResolvedJavaMethod(methodName), null);
 182         int actualOpNum = 0;
 183         for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) {
 184             if (predicate.test(ins)) {
 185                 actualOpNum++;
 186             }
 187         }
 188         Assert.assertEquals(expected, actualOpNum);
 189     }
 190 }