001/*
002 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023
024package com.oracle.graal.asm.amd64.test;
025
026import com.oracle.graal.asm.amd64.*;
027import com.oracle.graal.asm.test.*;
028
029import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.*;
030import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*;
031import static jdk.internal.jvmci.code.ValueUtil.*;
032import static jdk.internal.jvmci.common.UnsafeAccess.*;
033import static org.junit.Assume.*;
034
035import java.lang.reflect.*;
036import java.util.*;
037
038import jdk.internal.jvmci.amd64.*;
039import jdk.internal.jvmci.amd64.AMD64.*;
040import jdk.internal.jvmci.code.*;
041import jdk.internal.jvmci.meta.*;
042
043import org.junit.*;
044
045public class BitOpsTest extends AssemblerTest {
046    private static boolean lzcntSupported;
047    private static boolean tzcntSupported;
048
049    @Before
050    public void checkAMD64() {
051        assumeTrue("skipping AMD64 specific test", codeCache.getTarget().arch instanceof AMD64);
052        EnumSet<CPUFeature> features = ((AMD64) codeCache.getTarget().arch).getFeatures();
053        lzcntSupported = features.contains(CPUFeature.LZCNT);
054        tzcntSupported = features.contains(CPUFeature.BMI1);
055    }
056
057    @Test
058    public void lzcntlTest() {
059        if (lzcntSupported) {
060            CodeGenTest test = new CodeGenTest() {
061
062                @Override
063                public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
064                    AMD64Assembler asm = new AMD64Assembler(target, registerConfig);
065                    Register ret = registerConfig.getReturnRegister(Kind.Int);
066                    Register arg = asRegister(cc.getArgument(0));
067                    LZCNT.emit(asm, DWORD, ret, arg);
068                    asm.ret(0);
069                    return asm.close(true);
070                }
071            };
072            assertReturn("intStub", test, 31, 1);
073        }
074    }
075
076    @Test
077    public void lzcntlMemTest() {
078        if (lzcntSupported) {
079            CodeGenTest test = new CodeGenTest() {
080
081                @Override
082                public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
083                    AMD64Assembler asm = new AMD64Assembler(target, registerConfig);
084                    Register ret = registerConfig.getReturnRegister(Kind.Int);
085                    try {
086                        Field f = IntField.class.getDeclaredField("x");
087                        AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) unsafe.objectFieldOffset(f));
088                        LZCNT.emit(asm, DWORD, ret, arg);
089                        asm.ret(0);
090                        return asm.close(true);
091                    } catch (Exception e) {
092                        throw new RuntimeException("exception while trying to generate field access:", e);
093                    }
094                }
095            };
096            assertReturn("intFieldStub", test, 31, new IntField(1));
097        }
098    }
099
100    @Test
101    public void lzcntqTest() {
102        if (lzcntSupported) {
103            CodeGenTest test = new CodeGenTest() {
104
105                @Override
106                public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
107                    AMD64Assembler asm = new AMD64Assembler(target, registerConfig);
108                    Register ret = registerConfig.getReturnRegister(Kind.Int);
109                    Register arg = asRegister(cc.getArgument(0));
110                    LZCNT.emit(asm, QWORD, ret, arg);
111                    asm.ret(0);
112                    return asm.close(true);
113                }
114            };
115            assertReturn("longStub", test, 63, 1L);
116        }
117    }
118
119    @Test
120    public void lzcntqMemTest() {
121        if (lzcntSupported) {
122            CodeGenTest test = new CodeGenTest() {
123
124                @Override
125                public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
126                    AMD64Assembler asm = new AMD64Assembler(target, registerConfig);
127                    Register ret = registerConfig.getReturnRegister(Kind.Int);
128                    try {
129                        Field f = LongField.class.getDeclaredField("x");
130                        AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) unsafe.objectFieldOffset(f));
131                        LZCNT.emit(asm, QWORD, ret, arg);
132                        asm.ret(0);
133                        return asm.close(true);
134                    } catch (Exception e) {
135                        throw new RuntimeException("exception while trying to generate field access:", e);
136                    }
137                }
138            };
139            assertReturn("longFieldStub", test, 63, new LongField(1));
140        }
141    }
142
143    @Test
144    public void tzcntlTest() {
145        if (tzcntSupported) {
146            CodeGenTest test = new CodeGenTest() {
147
148                @Override
149                public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
150                    AMD64Assembler asm = new AMD64Assembler(target, registerConfig);
151                    Register ret = registerConfig.getReturnRegister(Kind.Int);
152                    Register arg = asRegister(cc.getArgument(0));
153                    TZCNT.emit(asm, DWORD, ret, arg);
154                    asm.ret(0);
155                    return asm.close(true);
156                }
157            };
158            assertReturn("intStub", test, 31, 0x8000_0000);
159        }
160    }
161
162    @Test
163    public void tzcntlMemTest() {
164        if (tzcntSupported) {
165            CodeGenTest test = new CodeGenTest() {
166
167                @Override
168                public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
169                    AMD64Assembler asm = new AMD64Assembler(target, registerConfig);
170                    Register ret = registerConfig.getReturnRegister(Kind.Int);
171                    try {
172                        Field f = IntField.class.getDeclaredField("x");
173                        AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) unsafe.objectFieldOffset(f));
174                        TZCNT.emit(asm, DWORD, ret, arg);
175                        asm.ret(0);
176                        return asm.close(true);
177                    } catch (Exception e) {
178                        throw new RuntimeException("exception while trying to generate field access:", e);
179                    }
180                }
181            };
182            assertReturn("intFieldStub", test, 31, new IntField(0x8000_0000));
183        }
184    }
185
186    @Test
187    public void tzcntqTest() {
188        if (tzcntSupported) {
189            CodeGenTest test = new CodeGenTest() {
190
191                @Override
192                public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
193                    AMD64Assembler asm = new AMD64Assembler(target, registerConfig);
194                    Register ret = registerConfig.getReturnRegister(Kind.Int);
195                    Register arg = asRegister(cc.getArgument(0));
196                    TZCNT.emit(asm, QWORD, ret, arg);
197                    asm.ret(0);
198                    return asm.close(true);
199                }
200            };
201            assertReturn("longStub", test, 63, 0x8000_0000_0000_0000L);
202        }
203    }
204
205    @Test
206    public void tzcntqMemTest() {
207        if (tzcntSupported) {
208            CodeGenTest test = new CodeGenTest() {
209
210                @Override
211                public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
212                    AMD64Assembler asm = new AMD64Assembler(target, registerConfig);
213                    Register ret = registerConfig.getReturnRegister(Kind.Int);
214                    try {
215                        Field f = LongField.class.getDeclaredField("x");
216                        AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) unsafe.objectFieldOffset(f));
217                        TZCNT.emit(asm, QWORD, ret, arg);
218                        asm.ret(0);
219                        return asm.close(true);
220                    } catch (Exception e) {
221                        throw new RuntimeException("exception while trying to generate field access:", e);
222                    }
223                }
224            };
225            assertReturn("longFieldStub", test, 63, new LongField(0x8000_0000_0000_0000L));
226        }
227    }
228
229    @SuppressWarnings("unused")
230    public static int intStub(int arg) {
231        return 0;
232    }
233
234    @SuppressWarnings("unused")
235    public static int longStub(long arg) {
236        return 0;
237    }
238
239    public static class IntField {
240        public int x;
241
242        IntField(int x) {
243            this.x = x;
244        }
245    }
246
247    public static class LongField {
248        public long x;
249
250        LongField(long x) {
251            this.x = x;
252        }
253    }
254
255    @SuppressWarnings("unused")
256    public static int intFieldStub(IntField arg) {
257        return 0;
258    }
259
260    @SuppressWarnings("unused")
261    public static int longFieldStub(LongField arg) {
262        return 0;
263    }
264}