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