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