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  */
  23 package org.graalvm.compiler.lir.test.alloc.trace;
  24 
  25 import static org.junit.Assert.assertEquals;
  26 import static org.junit.Assert.assertTrue;
  27 
  28 import java.util.HashSet;
  29 
  30 import org.junit.Before;
  31 import org.junit.Ignore;
  32 import org.junit.Test;
  33 
  34 import org.graalvm.compiler.core.common.LIRKind;
  35 import org.graalvm.compiler.lir.alloc.trace.ShadowedRegisterValue;
  36 import org.graalvm.compiler.lir.alloc.trace.TraceGlobalMoveResolutionPhase;
  37 
  38 import jdk.vm.ci.code.Register;
  39 import jdk.vm.ci.code.Register.RegisterCategory;
  40 import jdk.vm.ci.code.RegisterValue;
  41 import jdk.vm.ci.code.StackSlot;
  42 import jdk.vm.ci.meta.AllocatableValue;
  43 import jdk.vm.ci.meta.PlatformKind;
  44 import 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  */
  51 public 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 }