1 /* 2 * Copyright (c) 2013, 2016, 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 package org.graalvm.compiler.asm.amd64.test; 25 26 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.LZCNT; 27 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.TZCNT; 28 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD; 29 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD; 30 import static jdk.vm.ci.code.ValueUtil.asRegister; 31 import static org.junit.Assume.assumeTrue; 32 33 import java.lang.reflect.Field; 34 import java.util.EnumSet; 35 36 import jdk.vm.ci.amd64.AMD64; 37 import jdk.vm.ci.amd64.AMD64.CPUFeature; 38 import jdk.vm.ci.code.CallingConvention; 39 import jdk.vm.ci.code.Register; 40 import jdk.vm.ci.code.RegisterConfig; 41 import jdk.vm.ci.code.TargetDescription; 42 import jdk.vm.ci.meta.JavaKind; 43 44 import org.junit.Before; 45 import org.junit.Test; 46 47 import org.graalvm.compiler.asm.amd64.AMD64Address; 48 import org.graalvm.compiler.asm.amd64.AMD64Assembler; 49 import org.graalvm.compiler.asm.test.AssemblerTest; 50 import org.graalvm.compiler.code.CompilationResult; 51 52 public class BitOpsTest extends AssemblerTest { 53 private static boolean lzcntSupported; 54 private static boolean tzcntSupported; 55 56 @Before 57 public void checkAMD64() { 58 assumeTrue("skipping AMD64 specific test", codeCache.getTarget().arch instanceof AMD64); 59 EnumSet<CPUFeature> features = ((AMD64) codeCache.getTarget().arch).getFeatures(); 60 lzcntSupported = features.contains(CPUFeature.LZCNT); 61 tzcntSupported = features.contains(CPUFeature.BMI1); 62 } 63 64 @Test 65 public void lzcntlTest() { 66 if (lzcntSupported) { 67 CodeGenTest test = new CodeGenTest() { 68 69 @Override 70 public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) { 71 AMD64Assembler asm = new AMD64Assembler(target); 72 Register ret = registerConfig.getReturnRegister(JavaKind.Int); 73 Register arg = asRegister(cc.getArgument(0)); 74 LZCNT.emit(asm, DWORD, ret, arg); 75 asm.ret(0); 76 return asm.close(true); 77 } 78 }; 79 assertReturn("intStub", test, 31, 1); 80 } 81 } 82 83 @Test 84 public void lzcntlMemTest() { 85 if (lzcntSupported) { 86 CodeGenTest test = new CodeGenTest() { 87 88 @Override 89 public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) { 90 AMD64Assembler asm = new AMD64Assembler(target); 91 Register ret = registerConfig.getReturnRegister(JavaKind.Int); 92 try { 93 Field f = IntField.class.getDeclaredField("x"); 94 AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f)); 95 LZCNT.emit(asm, DWORD, ret, arg); 96 asm.ret(0); 97 return asm.close(true); 98 } catch (Exception e) { 99 throw new RuntimeException("exception while trying to generate field access:", e); 100 } 101 } 102 }; 103 assertReturn("intFieldStub", test, 31, new IntField(1)); 104 } 105 } 106 107 @Test 108 public void lzcntqTest() { 109 if (lzcntSupported) { 110 CodeGenTest test = new CodeGenTest() { 111 112 @Override 113 public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) { 114 AMD64Assembler asm = new AMD64Assembler(target); 115 Register ret = registerConfig.getReturnRegister(JavaKind.Int); 116 Register arg = asRegister(cc.getArgument(0)); 117 LZCNT.emit(asm, QWORD, ret, arg); 118 asm.ret(0); 119 return asm.close(true); 120 } 121 }; 122 assertReturn("longStub", test, 63, 1L); 123 } 124 } 125 126 @Test 127 public void lzcntqMemTest() { 128 if (lzcntSupported) { 129 CodeGenTest test = new CodeGenTest() { 130 131 @Override 132 public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) { 133 AMD64Assembler asm = new AMD64Assembler(target); 134 Register ret = registerConfig.getReturnRegister(JavaKind.Int); 135 try { 136 Field f = LongField.class.getDeclaredField("x"); 137 AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f)); 138 LZCNT.emit(asm, QWORD, ret, arg); 139 asm.ret(0); 140 return asm.close(true); 141 } catch (Exception e) { 142 throw new RuntimeException("exception while trying to generate field access:", e); 143 } 144 } 145 }; 146 assertReturn("longFieldStub", test, 63, new LongField(1)); 147 } 148 } 149 150 @Test 151 public void tzcntlTest() { 152 if (tzcntSupported) { 153 CodeGenTest test = new CodeGenTest() { 154 155 @Override 156 public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) { 157 AMD64Assembler asm = new AMD64Assembler(target); 158 Register ret = registerConfig.getReturnRegister(JavaKind.Int); 159 Register arg = asRegister(cc.getArgument(0)); 160 TZCNT.emit(asm, DWORD, ret, arg); 161 asm.ret(0); 162 return asm.close(true); 163 } 164 }; 165 assertReturn("intStub", test, 31, 0x8000_0000); 166 } 167 } 168 169 @Test 170 public void tzcntlMemTest() { 171 if (tzcntSupported) { 172 CodeGenTest test = new CodeGenTest() { 173 174 @Override 175 public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) { 176 AMD64Assembler asm = new AMD64Assembler(target); 177 Register ret = registerConfig.getReturnRegister(JavaKind.Int); 178 try { 179 Field f = IntField.class.getDeclaredField("x"); 180 AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f)); 181 TZCNT.emit(asm, DWORD, ret, arg); 182 asm.ret(0); 183 return asm.close(true); 184 } catch (Exception e) { 185 throw new RuntimeException("exception while trying to generate field access:", e); 186 } 187 } 188 }; 189 assertReturn("intFieldStub", test, 31, new IntField(0x8000_0000)); 190 } 191 } 192 193 @Test 194 public void tzcntqTest() { 195 if (tzcntSupported) { 196 CodeGenTest test = new CodeGenTest() { 197 198 @Override 199 public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) { 200 AMD64Assembler asm = new AMD64Assembler(target); 201 Register ret = registerConfig.getReturnRegister(JavaKind.Int); 202 Register arg = asRegister(cc.getArgument(0)); 203 TZCNT.emit(asm, QWORD, ret, arg); 204 asm.ret(0); 205 return asm.close(true); 206 } 207 }; 208 assertReturn("longStub", test, 63, 0x8000_0000_0000_0000L); 209 } 210 } 211 212 @Test 213 public void tzcntqMemTest() { 214 if (tzcntSupported) { 215 CodeGenTest test = new CodeGenTest() { 216 217 @Override 218 public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) { 219 AMD64Assembler asm = new AMD64Assembler(target); 220 Register ret = registerConfig.getReturnRegister(JavaKind.Int); 221 try { 222 Field f = LongField.class.getDeclaredField("x"); 223 AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f)); 224 TZCNT.emit(asm, QWORD, ret, arg); 225 asm.ret(0); 226 return asm.close(true); 227 } catch (Exception e) { 228 throw new RuntimeException("exception while trying to generate field access:", e); 229 } 230 } 231 }; 232 assertReturn("longFieldStub", test, 63, new LongField(0x8000_0000_0000_0000L)); 233 } 234 } 235 236 @SuppressWarnings("unused") 237 public static int intStub(int arg) { 238 return 0; 239 } 240 241 @SuppressWarnings("unused") 242 public static int longStub(long arg) { 243 return 0; 244 } 245 246 public static class IntField { 247 public int x; 248 249 IntField(int x) { 250 this.x = x; 251 } 252 } 253 254 public static class LongField { 255 public long x; 256 257 LongField(long x) { 258 this.x = x; 259 } 260 } 261 262 @SuppressWarnings("unused") 263 public static int intFieldStub(IntField arg) { 264 return 0; 265 } 266 267 @SuppressWarnings("unused") 268 public static int longFieldStub(LongField arg) { 269 return 0; 270 } 271 }