1/*
2 * Copyright (c) 2015, 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.lir.test.alloc.trace;
24
25import static org.junit.Assert.assertEquals;
26import static org.junit.Assert.assertTrue;
27
28import java.util.HashSet;
29
30import org.junit.Before;
31import org.junit.Ignore;
32import org.junit.Test;
33
34import org.graalvm.compiler.core.common.LIRKind;
35import org.graalvm.compiler.lir.alloc.trace.ShadowedRegisterValue;
36import org.graalvm.compiler.lir.alloc.trace.TraceGlobalMoveResolutionPhase;
37
38import jdk.vm.ci.code.Register;
39import jdk.vm.ci.code.Register.RegisterCategory;
40import jdk.vm.ci.code.RegisterValue;
41import jdk.vm.ci.code.StackSlot;
42import jdk.vm.ci.meta.AllocatableValue;
43import jdk.vm.ci.meta.PlatformKind;
44import jdk.vm.ci.meta.Value;
45
46/**
47 * Test global move resolver of the trace register allocator.
48 *
49 * Especially the mapping of LabelOp.incoming and BlockEndOp.outgoing.
50 */
51public class TraceGlobalMoveResolutionMappingTest {
52
53    private static final class MoveResolverMock extends TraceGlobalMoveResolutionPhase.MoveResolver {
54
55        private static final class Pair {
56
57            @Override
58            public int hashCode() {
59                final int prime = 31;
60                int result = 1;
61                result = prime * result + ((dst == null) ? 0 : dst.hashCode());
62                result = prime * result + ((src == null) ? 0 : src.hashCode());
63                return result;
64            }
65
66            @Override
67            public boolean equals(Object obj) {
68                if (this == obj) {
69                    return true;
70                }
71                if (obj == null) {
72                    return false;
73                }
74                if (getClass() != obj.getClass()) {
75                    return false;
76                }
77                Pair other = (Pair) obj;
78                if (dst == null) {
79                    if (other.dst != null) {
80                        return false;
81                    }
82                } else if (!dst.equals(other.dst)) {
83                    return false;
84                }
85                if (src == null) {
86                    if (other.src != null) {
87                        return false;
88                    }
89                } else if (!src.equals(other.src)) {
90                    return false;
91                }
92                return true;
93            }
94
95            private final Value src;
96            private final AllocatableValue dst;
97
98            Pair(Value src, AllocatableValue dst) {
99                this.src = src;
100                this.dst = dst;
101            }
102
103            @Override
104            public String toString() {
105                return dst.toString() + " <- " + src;
106            }
107        }
108
109        private final HashSet<Pair> mapping = new HashSet<>();
110
111        @Override
112        public void addMapping(Value src, AllocatableValue dst, Value srcStack) {
113            mapping.add(new Pair(src, dst));
114        }
115
116        public int size() {
117            return mapping.size();
118        }
119
120        public boolean contains(Value src, AllocatableValue dst) {
121            return mapping.contains(new Pair(src, dst));
122        }
123
124        @Override
125        public String toString() {
126            return mapping.toString();
127        }
128
129    }
130
131    private static final RegisterCategory CPU = new RegisterCategory("CPU");
132
133    private static final Register r0 = new Register(0, 0, "r0", CPU);
134    private static final Register r1 = new Register(1, 1, "r1", CPU);
135
136    private enum DummyPlatformKind implements PlatformKind {
137        Long;
138
139        private EnumKey<DummyPlatformKind> key = new EnumKey<>(this);
140
141        @Override
142        public Key getKey() {
143            return key;
144        }
145
146        @Override
147        public int getSizeInBytes() {
148            return 8;
149        }
150
151        @Override
152        public int getVectorLength() {
153            return 1;
154        }
155
156        @Override
157        public char getTypeChar() {
158            return 'l';
159        }
160    }
161
162    private static final LIRKind kind = LIRKind.value(DummyPlatformKind.Long);
163
164    private MoveResolverMock resolver;
165
166    @Before
167    public void setUp() {
168        resolver = new MoveResolverMock();
169    }
170
171    private void addMapping(Value src, Value dst) {
172        TraceGlobalMoveResolutionPhase.addMapping(resolver, src, dst);
173    }
174
175    /** Create RegisterValue. */
176    private static RegisterValue v(Register r) {
177        return r.asValue(kind);
178    }
179
180    /** Create StackSlot. */
181    private static StackSlot s(int offset) {
182        return StackSlot.get(kind, -offset, true);
183    }
184
185    /** Create ShadowedRegisterValue. */
186    private static ShadowedRegisterValue sd(Register reg, int offset) {
187        return new ShadowedRegisterValue(v(reg), s(offset));
188    }
189
190    private void assertContains(Value src, AllocatableValue dst) {
191        assertTrue(String.format("Expected move from %s to %s. %s", src, dst, resolver), resolver.contains(src, dst));
192    }
193
194    private void assertSize(int expected) {
195        assertEquals(resolver.toString(), expected, resolver.size());
196    }
197
198    @Test
199    public void testReg2Reg0() {
200        addMapping(v(r0), v(r1));
201        assertContains(v(r0), v(r1));
202    }
203
204    @Test
205    public void testReg2Reg1() {
206        addMapping(v(r0), v(r0));
207        assertSize(0);
208    }
209
210    @Test
211    public void testStack2Stack0() {
212        addMapping(s(1), s(2));
213        assertContains(s(1), s(2));
214    }
215
216    @Test
217    public void testStack2Stack1() {
218        addMapping(s(1), s(1));
219        assertSize(0);
220    }
221
222    @Test
223    public void testStack2Reg() {
224        addMapping(s(1), v(r1));
225        assertContains(s(1), v(r1));
226    }
227
228    @Test
229    public void testReg2Stack() {
230        addMapping(v(r0), s(1));
231        assertContains(v(r0), s(1));
232    }
233
234    @Test
235    public void testShadowed2Reg() {
236        addMapping(sd(r0, 1), v(r1));
237        assertContains(v(r0), v(r1));
238    }
239
240    @Test
241    public void testReg2Shadowed0() {
242        addMapping(v(r0), sd(r1, 1));
243        assertSize(2);
244        assertContains(v(r0), v(r1));
245        assertContains(v(r0), s(1));
246    }
247
248    @Test
249    public void testReg2Shadowed1() {
250        addMapping(v(r0), sd(r0, 1));
251        assertSize(1);
252        assertContains(v(r0), s(1));
253    }
254
255    @Test
256    @Ignore("Cannot express mapping dependencies (yet)")
257    public void testStack2Shadowed0() {
258        addMapping(s(2), sd(r1, 1));
259        assertSize(2);
260        assertContains(s(2), v(r1));
261        assertContains(v(r1), s(1));
262    }
263
264    @Test
265    public void testStack2Shadowed0WorkArount() {
266        addMapping(s(2), sd(r1, 1));
267        assertSize(2);
268        assertContains(s(2), v(r1));
269        assertContains(s(2), s(1));
270    }
271
272    @Test
273    public void testStack2Shadowed1() {
274        addMapping(s(1), sd(r1, 1));
275        assertSize(1);
276        assertContains(s(1), v(r1));
277    }
278
279    @Test
280    public void testShadowed2Shadowed0() {
281        addMapping(sd(r0, 1), sd(r1, 2));
282        assertSize(2);
283        assertContains(v(r0), v(r1));
284        assertContains(v(r0), s(2));
285    }
286
287    @Test
288    public void testShadowed2Shadowed1() {
289        addMapping(sd(r0, 1), sd(r1, 1));
290        assertSize(1);
291        assertContains(v(r0), v(r1));
292    }
293
294    @Test
295    public void testShadowed2Shadowed2() {
296        addMapping(sd(r0, 1), sd(r0, 1));
297        assertSize(0);
298    }
299}
300