/* * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package org.graalvm.compiler.core.aarch64.test; import static org.junit.Assume.assumeTrue; import java.util.function.Predicate; import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; import org.graalvm.compiler.lir.LIR; import org.graalvm.compiler.lir.LIRInstruction; import org.graalvm.compiler.lir.LIRInstructionClass; import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow; import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; import org.graalvm.compiler.lir.gen.LIRGenerationResult; import org.graalvm.compiler.lir.gen.LIRGeneratorTool; import org.graalvm.compiler.lir.jtt.LIRTest; import org.graalvm.compiler.lir.jtt.LIRTestSpecification; import org.graalvm.compiler.lir.phases.LIRPhase; import org.graalvm.compiler.lir.phases.LIRSuites; import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext; import org.graalvm.compiler.options.OptionValues; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.meta.Value; public class AArch64TestBitAndBranchTest extends LIRTest { private static final Predicate checkForBitTestAndBranchOp = op -> (op instanceof AArch64ControlFlow.BitTestAndBranchOp); private LIR lir; @Before public void checkAArch64() { assumeTrue("skipping AArch64 specific test", getTarget().arch instanceof AArch64); } public static long testBit42Snippet(long a, long b, long c) { if ((a & (1 << 42)) == 0) { return b; } else { return c; } } @Test public void testBit42() { test("testBit42Snippet", 1L << 42L, Long.MAX_VALUE, Long.MIN_VALUE); test("testBit42Snippet", ~(1L << 42L), Long.MAX_VALUE, Long.MIN_VALUE); checkLIR("testBit42Snippet", checkForBitTestAndBranchOp, 1); } private static final LargeOpSpec largeOpSingleNop = new LargeOpSpec((1 << 14 - 2), 2); /** * Tests the graceful case, where the estimation for * {@link CompilationResultBuilder#labelWithinRange(LIRInstruction, org.graalvm.compiler.asm.Label, int)} * holds. */ public static int testBitTestAndBranchSingleSnippet(int a) { int res; if (a % 2 == 0) { res = fillOps(largeOpSingleNop, 1); } else { res = fillOps(largeOpSingleNop, 2); } return GraalDirectives.opaque(res); } @Test public void testBitTestAndBranchSingle() { runTest("testBitTestAndBranchSingleSnippet", 1); checkLIR("testBitTestAndBranchSingleSnippet", checkForBitTestAndBranchOp, 1); } private static final LargeOpSpec largeOpFourNop = new LargeOpSpec((1 << 14 - 2), 8); /** * Tests the case, where the estimation for * {@link CompilationResultBuilder#labelWithinRange(LIRInstruction, org.graalvm.compiler.asm.Label, int)} * does not hold and the code generation must be redone with large branches. */ public static int testBitTestAndBranchFourSnippet(int a) { int res; if (a % 2 == 0) { res = fillOps(largeOpFourNop, 1); } else { res = fillOps(largeOpFourNop, 2); } return GraalDirectives.opaque(res); } @Test public void testBitTestAndBranchFour() { runTest("testBitTestAndBranchFourSnippet", 1); checkLIR("testBitTestAndBranchFourSnippet", checkForBitTestAndBranchOp, 1); } private static class LargeOpSpec extends LIRTestSpecification { private final int n; private final int nopCount; LargeOpSpec(int n, int nopCount) { super(); this.n = n; this.nopCount = nopCount; } @Override public void generate(LIRGeneratorTool gen, Value a) { for (int i = 0; i < n; i++) { gen.append(new NoOp(nopCount)); } setResult(a); } } public static class NoOp extends AArch64LIRInstruction { private static final LIRInstructionClass TYPE = LIRInstructionClass.create(NoOp.class); private final int nopCount; public NoOp(int nopCount) { super(TYPE); this.nopCount = nopCount; } @Override protected void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { for (int i = 0; i < nopCount; i++) { masm.nop(); } } } @LIRIntrinsic public static int fillOps(@SuppressWarnings("unused") LargeOpSpec s, int a) { return a; } @Override protected LIRSuites createLIRSuites(OptionValues options) { LIRSuites suites = super.createLIRSuites(options); suites.getPreAllocationOptimizationStage().appendPhase(new CheckPhase()); return suites; } public class CheckPhase extends LIRPhase { @Override protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PreAllocationOptimizationContext context) { lir = lirGenRes.getLIR(); } } protected void checkLIR(String methodName, Predicate predicate, int expected) { compile(getResolvedJavaMethod(methodName), null); int actualOpNum = 0; for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) { if (predicate.test(ins)) { actualOpNum++; } } Assert.assertEquals(expected, actualOpNum); } }