1/*
2 * Copyright (c) 2015, 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 */
23package org.graalvm.compiler.asm.amd64.test;
24
25import static jdk.vm.ci.code.ValueUtil.asRegister;
26import static org.junit.Assume.assumeTrue;
27
28import java.lang.reflect.Field;
29
30import jdk.vm.ci.amd64.AMD64;
31import jdk.vm.ci.code.CallingConvention;
32import jdk.vm.ci.code.Register;
33import jdk.vm.ci.code.RegisterConfig;
34import jdk.vm.ci.code.TargetDescription;
35import jdk.vm.ci.meta.JavaKind;
36
37import org.junit.Before;
38import org.junit.Test;
39
40import org.graalvm.compiler.asm.amd64.AMD64Address;
41import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
42import org.graalvm.compiler.asm.test.AssemblerTest;
43import org.graalvm.compiler.code.CompilationResult;
44
45public class IncrementDecrementMacroTest extends AssemblerTest {
46
47    @Before
48    public void checkAMD64() {
49        assumeTrue("skipping AMD64 specific test", codeCache.getTarget().arch instanceof AMD64);
50    }
51
52    public static class LongField {
53        public long x;
54
55        LongField(long x) {
56            this.x = x;
57        }
58    }
59
60    private static class IncrementCodeGenTest implements CodeGenTest {
61        final int value;
62
63        IncrementCodeGenTest(int value) {
64            this.value = value;
65        }
66
67        @Override
68        public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
69            AMD64MacroAssembler asm = new AMD64MacroAssembler(target);
70            Register ret = registerConfig.getReturnRegister(JavaKind.Int);
71            try {
72                Field f = LongField.class.getDeclaredField("x");
73                AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f));
74                asm.incrementq(arg, value);
75                asm.movq(ret, arg);
76                asm.ret(0);
77                return asm.close(true);
78            } catch (Exception e) {
79                throw new RuntimeException("exception while trying to generate field access:", e);
80            }
81        }
82    }
83
84    private void assertIncrement(long initValue, int increment) {
85        assertReturn("longFieldStubIncrement", new IncrementCodeGenTest(increment), initValue + increment, new LongField(initValue));
86    }
87
88    private void assertIncrements(int increment) {
89        assertIncrement(0x4242_4242_4242_4242L, increment);
90    }
91
92    @SuppressWarnings("unused")
93    public static long longFieldStubIncrement(LongField arg) {
94        return 0;
95    }
96
97    private static class DecrementCodeGenTest implements CodeGenTest {
98        final int value;
99
100        DecrementCodeGenTest(int value) {
101            this.value = value;
102        }
103
104        @Override
105        public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
106            AMD64MacroAssembler asm = new AMD64MacroAssembler(target);
107            Register ret = registerConfig.getReturnRegister(JavaKind.Int);
108            try {
109                Field f = LongField.class.getDeclaredField("x");
110                AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f));
111                asm.decrementq(arg, value);
112                asm.movq(ret, arg);
113                asm.ret(0);
114                return asm.close(true);
115            } catch (Exception e) {
116                throw new RuntimeException("exception while trying to generate field access:", e);
117            }
118        }
119    }
120
121    private void assertDecrement(long initValue, int increment) {
122        assertReturn("longFieldStubDecrement", new DecrementCodeGenTest(increment), initValue - increment, new LongField(initValue));
123    }
124
125    private void assertDecrements(int increment) {
126        assertDecrement(0x4242_4242_4242_4242L, increment);
127    }
128
129    @SuppressWarnings("unused")
130    public static long longFieldStubDecrement(LongField arg) {
131        return 0;
132    }
133
134    @Test
135    public void incrementMemTest0() {
136        int increment = 0;
137        assertIncrements(increment);
138    }
139
140    @Test
141    public void incrementMemTest1() {
142        int increment = 1;
143        assertIncrements(increment);
144    }
145
146    @Test
147    public void incrementMemTest2() {
148        int increment = 2;
149        assertIncrements(increment);
150    }
151
152    @Test
153    public void incrementMemTest3() {
154        int increment = Integer.MAX_VALUE;
155        assertIncrements(increment);
156    }
157
158    @Test
159    public void incrementMemTest4() {
160        int increment = Integer.MIN_VALUE;
161        assertIncrements(increment);
162    }
163
164    @Test
165    public void incrementMemTest5() {
166        int increment = -1;
167        assertIncrements(increment);
168    }
169
170    @Test
171    public void incrementMemTest6() {
172        int increment = -2;
173        assertIncrements(increment);
174    }
175
176    @Test
177    public void incrementMemTest7() {
178        int increment = -0x1000_0000;
179        assertIncrements(increment);
180    }
181
182    @Test
183    public void decrementMemTest0() {
184        int decrement = 0;
185        assertDecrements(decrement);
186    }
187
188    @Test
189    public void decrementMemTest1() {
190        int decrement = 1;
191        assertDecrements(decrement);
192    }
193
194    @Test
195    public void decrementMemTest2() {
196        int decrement = 2;
197        assertDecrements(decrement);
198    }
199
200    @Test
201    public void decrementMemTest3() {
202        int decrement = Integer.MAX_VALUE;
203        assertDecrements(decrement);
204    }
205
206    @Test
207    public void decrementMemTest4() {
208        int decrement = Integer.MIN_VALUE;
209        assertDecrements(decrement);
210    }
211
212    @Test
213    public void decrementMemTest5() {
214        int decrement = -1;
215        assertDecrements(decrement);
216    }
217
218    @Test
219    public void decrementMemTest6() {
220        int decrement = -2;
221        assertDecrements(decrement);
222    }
223
224    @Test
225    public void decrementMemTest7() {
226        int decrement = -0x1000_0000;
227        assertDecrements(decrement);
228    }
229
230}
231