/* * Copyright (c) 2014, 2015, 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. * */ import jdk.test.lib.Asserts; import jdk.test.lib.Platform; import jdk.test.lib.Utils; import sun.hotspot.code.NMethod; import sun.hotspot.cpuinfo.CPUInfo; import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.util.concurrent.Callable; import java.util.function.Function; import compiler.whitebox.CompilerWhiteBoxTest; public class BmiIntrinsicBase extends CompilerWhiteBoxTest { protected BmiIntrinsicBase(BmiTestCase testCase) { super(testCase); } public static void verifyTestCase(Function constructor, Method... methods) throws Exception { for (Method method : methods) { new BmiIntrinsicBase(constructor.apply(method)).test(); } } @Override protected void test() throws Exception { BmiTestCase bmiTestCase = (BmiTestCase) testCase; if (!(Platform.isX86() || Platform.isX64())) { System.out.println("Unsupported platform, test SKIPPED"); return; } if (!Platform.isServer()) { System.out.println("Not server VM, test SKIPPED"); return; } if (!CPUInfo.hasFeature(bmiTestCase.getCpuFlag())) { System.out.println("Unsupported hardware, no required CPU flag " + bmiTestCase.getCpuFlag() + " , test SKIPPED"); return; } if (!Boolean.valueOf(getVMOption(bmiTestCase.getVMFlag()))) { System.out.println("VM flag " + bmiTestCase.getVMFlag() + " disabled, test SKIPPED"); return; } System.out.println(testCase.name()); switch (MODE) { case "compiled mode": case "mixed mode": if (TIERED_COMPILATION && TIERED_STOP_AT_LEVEL != CompilerWhiteBoxTest.COMP_LEVEL_MAX) { System.out.println("TieredStopAtLevel value (" + TIERED_STOP_AT_LEVEL + ") is too low, test SKIPPED"); return; } deoptimize(); compileAtLevelAndCheck(CompilerWhiteBoxTest.COMP_LEVEL_MAX); break; case "interpreted mode": // test is not applicable in this mode; System.err.println("Warning: This test is not applicable in mode: " + MODE); break; default: throw new AssertionError("Test bug, unknown VM mode: " + MODE); } } protected void compileAtLevelAndCheck(int level) { WHITE_BOX.enqueueMethodForCompilation(method, level); waitBackgroundCompilation(); checkCompilation(method, level); checkEmittedCode(method); } protected void checkCompilation(Executable executable, int level) { if (!WHITE_BOX.isMethodCompiled(executable)) { throw new AssertionError("Test bug, expected compilation (level): " + level + ", but not compiled" + WHITE_BOX.isMethodCompilable(executable, level)); } final int compilationLevel = WHITE_BOX.getMethodCompilationLevel(executable); if (compilationLevel != level) { throw new AssertionError("Test bug, expected compilation (level): " + level + ", but level: " + compilationLevel); } } protected void checkEmittedCode(Executable executable) { final byte[] nativeCode = NMethod.get(executable, false).insts; if (!((BmiTestCase) testCase).verifyPositive(nativeCode)) { throw new AssertionError(testCase.name() + "CPU instructions expected not found: " + Utils.toHexString(nativeCode)); } else { System.out.println("CPU instructions found, PASSED"); } } abstract static class BmiTestCase implements CompilerWhiteBoxTest.TestCase { private final Method method; protected byte[] instrMask; protected byte[] instrPattern; protected boolean isLongOperation; public BmiTestCase(Method method) { this.method = method; } @Override public String name() { return method.toGenericString(); } @Override public Executable getExecutable() { return method; } @Override public Callable getCallable() { return null; } @Override public boolean isOsr() { return false; } protected int countCpuInstructions(byte[] nativeCode) { return countCpuInstructions(nativeCode, instrMask, instrPattern); } public static int countCpuInstructions(byte[] nativeCode, byte[] instrMask, byte[] instrPattern) { int count = 0; int patternSize = Math.min(instrMask.length, instrPattern.length); boolean found; Asserts.assertGreaterThan(patternSize, 0); for (int i = 0, n = nativeCode.length - patternSize; i < n; i++) { found = true; for (int j = 0; j < patternSize; j++) { if ((nativeCode[i + j] & instrMask[j]) != instrPattern[j]) { found = false; break; } } if (found) { ++count; i += patternSize - 1; } } return count; } public boolean verifyPositive(byte[] nativeCode) { final int cnt = countCpuInstructions(nativeCode); if (Platform.isX86()) { return cnt >= (isLongOperation ? 2 : 1); } else { return Platform.isX64() && cnt >= 1; } } protected String getCpuFlag() { return "bmi1"; } protected String getVMFlag() { return "UseBMI1Instructions"; } } abstract static class BmiTestCase_x64 extends BmiTestCase { protected byte[] instrMask_x64; protected byte[] instrPattern_x64; protected BmiTestCase_x64(Method method) { super(method); } protected int countCpuInstructions(byte[] nativeCode) { int cnt = super.countCpuInstructions(nativeCode); if (Platform.isX64()) { // on x64 platform the instruction we search for can be encoded in 2 different ways cnt += countCpuInstructions(nativeCode, instrMask_x64, instrPattern_x64); } return cnt; } } }