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 }