1 /* 2 * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2020, Arm Limited. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 package compiler.vectorization.aarch64; 26 27 import java.lang.annotation.ElementType; 28 import java.lang.annotation.Retention; 29 import java.lang.annotation.RetentionPolicy; 30 import java.lang.annotation.Target; 31 import java.lang.reflect.Method; 32 33 import jdk.test.lib.process.OutputAnalyzer; 34 import jdk.test.lib.process.ProcessTools; 35 36 import sun.hotspot.WhiteBox; 37 import sun.hotspot.cpuinfo.CPUInfo; 38 39 import compiler.whitebox.CompilerWhiteBoxTest; 40 41 public class CodegenTestRunner { 42 43 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 44 45 @Target(ElementType.METHOD) 46 @Retention(RetentionPolicy.RUNTIME) 47 protected @interface CallMath {} 48 49 @Target(ElementType.METHOD) 50 @Retention(RetentionPolicy.RUNTIME) 51 protected @interface CheckOpto { 52 String neon() default ""; 53 String sve() default ""; 54 String sve2() default ""; 55 } 56 57 private void checkMethod(Method method, int sveLevel) throws Exception { 58 String className = getClass().getName(); 59 String methodName = method.getName(); 60 61 // Check if test method is valid 62 if (method.getParameterCount() > 0) { 63 throw new RuntimeException("Test method should have zero parameter"); 64 } 65 66 // Find expected NEON/SVE instructions from the annotation 67 CheckOpto optos = method.getAnnotation(CheckOpto.class); 68 String opcodes, suffix; 69 switch (sveLevel) { 70 case 0: 71 opcodes = optos.neon(); 72 suffix = "# vector \\([0-9]+[A-Z]+\\)"; // 16B, 8H, 4S, 2D, ... 73 break; 74 case 1: 75 opcodes = optos.sve(); 76 suffix = "\\(sve\\)"; 77 break; 78 case 2: 79 opcodes = optos.sve2(); 80 suffix = "\\(sve2\\)"; 81 break; 82 default: 83 throw new RuntimeException("Unexpected SVE level"); 84 } 85 86 // Skip this check if the expected instruction is not defined 87 if (opcodes.equals("")) { 88 return; 89 } 90 91 // Create a process to compile specified method 92 String[] procArgs = { 93 "-Xbootclasspath/a:.", 94 "-XX:+IgnoreUnrecognizedVMOptions", 95 "-XX:+WhiteBoxAPI", 96 "-XX:-BackgroundCompilation", 97 "-XX:+PrintOptoAssembly", 98 "-XX:UseSVE=" + sveLevel, 99 "-XX:CompileOnly=" + className + "::" + methodName, 100 className, 101 methodName 102 }; 103 ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(procArgs); 104 OutputAnalyzer output = new OutputAnalyzer(pb.start()); 105 106 // The sub-process should exit with no error 107 output.shouldHaveExitValue(0); 108 output.stderrShouldBeEmptyIgnoreVMWarnings(); 109 110 // Pattern match of the printed OptoAssembly to check the existence of 111 // expected SIMD instructions 112 // E.g. 113 // 27c sve_add V16, V17, V16 # vector (sve) 114 // matches 115 // "{SPACES}{opc}{SPACES}{ANYTHING}{suffix}" 116 for (String opc : opcodes.split("\\|")) { 117 // Check comma-separated opto instructions 118 String regex = "\\s+" + opc + "\\s+.+" + suffix; 119 output.stdoutShouldMatch(regex); 120 } 121 } 122 123 private void testMethodsWithSVELevel(int sveLevel) { 124 Class testClass = getClass(); 125 for (Method testMethod : testClass.getDeclaredMethods()) { 126 // Check all methods with CheckOpto annotation 127 if (testMethod.isAnnotationPresent(CheckOpto.class)) { 128 try { 129 checkMethod(testMethod, sveLevel); 130 } catch (Exception e) { 131 // Report failed case and exit 132 System.err.println("Test failed in " + testClass.getName() + 133 "." + testMethod.getName() + ": " + e.getMessage()); 134 System.exit(1); 135 } 136 } 137 } 138 } 139 140 private void checkCPUFeatureAndRun() { 141 if (CPUInfo.hasFeature("sve2")) { 142 testMethodsWithSVELevel(2); 143 } 144 if (CPUInfo.hasFeature("sve")) { 145 testMethodsWithSVELevel(1); 146 } 147 // always check NEON 148 testMethodsWithSVELevel(0); 149 } 150 151 private void compileMethodByName(String methodName) { 152 try { 153 Method method = getClass().getDeclaredMethod(methodName); 154 if (method.isAnnotationPresent(CallMath.class)) { 155 // For method that calls intrinsified math methods, the class 156 // java.lang.Math should be loaded before the compilation to 157 // avoid C2 generating unexpected uncommon traps 158 try { 159 Class.forName("java.lang.Math"); 160 } catch (ClassNotFoundException e) { 161 System.err.println("Failed to load class java.lang.Math"); 162 } 163 } 164 WHITE_BOX.enqueueMethodForCompilation( 165 method, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); 166 } catch (NoSuchMethodException e) { 167 System.err.println("Method " + methodName + " not found"); 168 } 169 } 170 171 protected void run(String[] args) { 172 if (args.length == 0) { 173 // We are in the main java process running the test runner 174 // Create sub-processes to run the case with all supported SVE level 175 checkCPUFeatureAndRun(); 176 } else if (args.length == 1) { 177 // We are in the forked java process running the case 178 // Compile the method specified by args[0] for SIMD instruction check 179 compileMethodByName(args[0]); 180 } else { 181 System.err.println("Unexpected args[] length"); 182 System.exit(1); 183 } 184 } 185 } 186