1 /* 2 * Copyright (c) 2014, 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 import com.oracle.java.testlibrary.Asserts; 26 import com.oracle.java.testlibrary.Platform; 27 import com.oracle.java.testlibrary.Utils; 28 import jdk.testlib.code.NMethod; 29 import jdk.testlib.cpuinfo.CPUInfo; 30 31 import java.lang.reflect.Executable; 32 import java.lang.reflect.Method; 33 import java.util.concurrent.Callable; 34 import java.util.function.Function; 35 36 public class BmiIntrinsicBase extends CompilerWhiteBoxTest { 37 38 protected BmiIntrinsicBase(BmiTestCase testCase) { 39 super(testCase); 40 } 41 42 public static void verifyTestCase(Function<Method, BmiTestCase> constructor, Method... methods) throws Exception { 43 for (Method method : methods) { 44 new BmiIntrinsicBase(constructor.apply(method)).test(); 45 } 46 } 47 48 @Override 49 protected void test() throws Exception { 50 BmiTestCase bmiTestCase = (BmiTestCase) testCase; 51 52 if (!(Platform.isX86() || Platform.isX64())) { 53 System.out.println("Unsupported platform, test SKIPPED"); 54 return; 55 } 56 57 if (!Platform.isServer()) { 58 System.out.println("Not server VM, test SKIPPED"); 59 return; 60 } 61 62 if (!CPUInfo.hasFeature(bmiTestCase.getCpuFlag())) { 63 System.out.println("Unsupported hardware, no required CPU flag " + bmiTestCase.getCpuFlag() + " , test SKIPPED"); 64 return; 65 } 66 67 if (!Boolean.valueOf(getVMOption(bmiTestCase.getVMFlag()))) { 68 System.out.println("VM flag " + bmiTestCase.getVMFlag() + " disabled, test SKIPPED"); 69 return; 70 } 71 72 System.out.println(testCase.name()); 73 74 switch (MODE) { 75 case "compiled mode": 76 case "mixed mode": 77 if (TIERED_COMPILATION && TIERED_STOP_AT_LEVEL != CompilerWhiteBoxTest.COMP_LEVEL_MAX) { 78 System.out.println("TieredStopAtLevel value (" + TIERED_STOP_AT_LEVEL + ") is too low, test SKIPPED"); 79 return; 80 } 81 deoptimize(); 82 compileAtLevelAndCheck(CompilerWhiteBoxTest.COMP_LEVEL_MAX); 83 break; 84 case "interpreted mode": // test is not applicable in this mode; 85 System.err.println("Warning: This test is not applicable in mode: " + MODE); 86 break; 87 default: 88 throw new AssertionError("Test bug, unknown VM mode: " + MODE); 89 } 90 } 91 92 protected void compileAtLevelAndCheck(int level) { 93 WHITE_BOX.enqueueMethodForCompilation(method, level); 94 waitBackgroundCompilation(); 95 checkCompilation(method, level); 96 checkEmittedCode(method); 97 } 98 99 protected void checkCompilation(Executable executable, int level) { 100 if (!WHITE_BOX.isMethodCompiled(executable)) { 101 throw new AssertionError("Test bug, expected compilation (level): " + level + ", but not compiled" + WHITE_BOX.isMethodCompilable(executable, level)); 102 } 103 final int compilationLevel = WHITE_BOX.getMethodCompilationLevel(executable); 104 if (compilationLevel != level) { 105 throw new AssertionError("Test bug, expected compilation (level): " + level + ", but level: " + compilationLevel); 106 } 107 } 108 109 protected void checkEmittedCode(Executable executable) { 110 final byte[] nativeCode = NMethod.get(executable, false).insts; 111 if (!((BmiTestCase) testCase).verifyPositive(nativeCode)) { 112 throw new AssertionError(testCase.name() + "CPU instructions expected not found: " + Utils.toHexString(nativeCode)); 113 } else { 114 System.out.println("CPU instructions found, PASSED"); 115 } 116 } 117 118 abstract static class BmiTestCase implements CompilerWhiteBoxTest.TestCase { 119 private final Method method; 120 protected byte[] instrMask; 121 protected byte[] instrPattern; 122 protected boolean isLongOperation; 123 124 public BmiTestCase(Method method) { 125 this.method = method; 126 } 127 128 @Override 129 public String name() { 130 return method.toGenericString(); 131 } 132 133 @Override 134 public Executable getExecutable() { 135 return method; 136 } 137 138 @Override 139 public Callable<Integer> getCallable() { 140 return null; 141 } 142 143 @Override 144 public boolean isOsr() { 145 return false; 146 } 147 148 protected int countCpuInstructions(byte[] nativeCode) { 149 return countCpuInstructions(nativeCode, instrMask, instrPattern); 150 } 151 152 public static int countCpuInstructions(byte[] nativeCode, byte[] instrMask, byte[] instrPattern) { 153 int count = 0; 154 int patternSize = Math.min(instrMask.length, instrPattern.length); 155 boolean found; 156 Asserts.assertGreaterThan(patternSize, 0); 157 for (int i = 0, n = nativeCode.length - patternSize; i < n; i++) { 158 found = true; 159 for (int j = 0; j < patternSize; j++) { 160 if ((nativeCode[i + j] & instrMask[j]) != instrPattern[j]) { 161 found = false; 162 break; 163 } 164 } 165 if (found) { 166 ++count; 167 i += patternSize - 1; 168 } 169 } 170 return count; 171 } 172 173 public boolean verifyPositive(byte[] nativeCode) { 174 final int cnt = countCpuInstructions(nativeCode); 175 if (Platform.isX86()) { 176 return cnt >= (isLongOperation ? 2 : 1); 177 } else { 178 return Platform.isX64() && cnt >= 1; 179 } 180 } 181 182 protected String getCpuFlag() { 183 return "bmi1"; 184 } 185 186 protected String getVMFlag() { 187 return "UseBMI1Instructions"; 188 } 189 } 190 191 abstract static class BmiTestCase_x64 extends BmiTestCase { 192 protected byte[] instrMask_x64; 193 protected byte[] instrPattern_x64; 194 195 protected BmiTestCase_x64(Method method) { 196 super(method); 197 } 198 199 protected int countCpuInstructions(byte[] nativeCode) { 200 int cnt = super.countCpuInstructions(nativeCode); 201 if (Platform.isX64()) { // on x64 platform the instruction we search for can be encoded in 2 different ways 202 cnt += countCpuInstructions(nativeCode, instrMask_x64, instrPattern_x64); 203 } 204 return cnt; 205 } 206 } 207 }