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
24package org.graalvm.compiler.asm.amd64.test;
25
26import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.LZCNT;
27import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.TZCNT;
28import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD;
29import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD;
30import static jdk.vm.ci.code.ValueUtil.asRegister;
31import static org.junit.Assume.assumeTrue;
32
33import java.lang.reflect.Field;
34import java.util.EnumSet;
35
36import jdk.vm.ci.amd64.AMD64;
37import jdk.vm.ci.amd64.AMD64.CPUFeature;
38import jdk.vm.ci.code.CallingConvention;
39import jdk.vm.ci.code.Register;
40import jdk.vm.ci.code.RegisterConfig;
41import jdk.vm.ci.code.TargetDescription;
42import jdk.vm.ci.meta.JavaKind;
43
44import org.junit.Before;
45import org.junit.Test;
46
47import org.graalvm.compiler.asm.amd64.AMD64Address;
48import org.graalvm.compiler.asm.amd64.AMD64Assembler;
49import org.graalvm.compiler.asm.test.AssemblerTest;
50import org.graalvm.compiler.code.CompilationResult;
51
52public 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}
272