1 /* 2 * Copyright (c) 2015, 2018, 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 24 25 package org.graalvm.compiler.core.amd64.test; 26 27 import static org.junit.Assume.assumeTrue; 28 29 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; 30 import org.graalvm.compiler.core.test.MatchRuleTest; 31 import org.graalvm.compiler.lir.LIR; 32 import org.graalvm.compiler.lir.LIRInstruction; 33 import org.graalvm.compiler.lir.amd64.AMD64Binary; 34 import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer.MemoryConstOp; 35 import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer.ConstOp; 36 import org.graalvm.compiler.lir.amd64.AMD64Unary; 37 import org.junit.Before; 38 import org.junit.Test; 39 40 import jdk.vm.ci.amd64.AMD64; 41 import jdk.vm.ci.amd64.AMD64Kind; 42 43 public class AMD64MatchRuleTest extends MatchRuleTest { 44 @Before 45 public void checkAMD64() { 46 assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64); 47 } 48 49 public static int test1Snippet(TestClass o, TestClass b, TestClass c) { 50 if (o.x == 42) { 51 return b.z; 52 } else { 53 return c.y; 54 } 55 } 56 57 /** 58 * Verifies, if the match rules in AMD64NodeMatchRules do work on the graphs by compiling and 59 * checking if the expected LIR instruction show up. 60 */ 61 @Test 62 public void test1() { 63 compile(getResolvedJavaMethod("test1Snippet"), null); 64 LIR lir = getLIR(); 65 boolean found = false; 66 for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) { 67 if (ins instanceof MemoryConstOp && ((MemoryConstOp) ins).getOpcode().toString().equals("CMP")) { 68 assertFalse("MemoryConstOp expected only once in first block", found); 69 found = true; 70 } 71 } 72 assertTrue("Memory compare must be in the LIR", found); 73 } 74 75 public static class TestClass { 76 public int x; 77 public int y; 78 public int z; 79 80 public TestClass(int x) { 81 super(); 82 this.x = x; 83 } 84 } 85 86 static volatile short shortValue; 87 88 public static long testVolatileExtensionSnippet() { 89 return shortValue; 90 } 91 92 @Test 93 public void testVolatileExtension() { 94 compile(getResolvedJavaMethod("testVolatileExtensionSnippet"), null); 95 LIR lir = getLIR(); 96 boolean found = false; 97 for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) { 98 if (ins instanceof AMD64Unary.MemoryOp) { 99 ins.visitEachOutput((value, mode, flags) -> assertTrue(value.getPlatformKind().toString(), value.getPlatformKind().equals(AMD64Kind.QWORD))); 100 assertFalse("MemoryOp expected only once in first block", found); 101 found = true; 102 } 103 } 104 assertTrue("sign extending load must be in the LIR", found); 105 } 106 107 static int intValue; 108 static volatile int volatileIntValue; 109 110 /** 111 * Can't match test and load of input because of volatile store in between. 112 */ 113 public static short testLoadTestNoMatchSnippet() { 114 int v = intValue; 115 volatileIntValue = 42; 116 if (v == 42) { 117 return shortValue; 118 } 119 return 0; 120 } 121 122 @Test 123 public void testLoadTestNoMatch() { 124 compile(getResolvedJavaMethod("testLoadTestNoMatchSnippet"), null); 125 LIR lir = getLIR(); 126 boolean found = false; 127 for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) { 128 if (ins instanceof ConstOp && ((ConstOp) ins).getOpcode().toString().equals("CMP")) { 129 assertFalse("CMP expected only once in first block", found); 130 found = true; 131 } 132 } 133 assertTrue("CMP must be in the LIR", found); 134 } 135 136 /** 137 * Should match as an add with a memory operand. 138 */ 139 public static int testAddLoadSnippet() { 140 int v1 = volatileIntValue; 141 int v2 = intValue; 142 return v2 + (2 * v1); 143 } 144 145 @Test 146 public void testAddLoad() { 147 compile(getResolvedJavaMethod("testAddLoadSnippet"), null); 148 LIR lir = getLIR(); 149 boolean found = false; 150 for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) { 151 if (ins instanceof AMD64Binary.MemoryTwoOp && ((AMD64Binary.MemoryTwoOp) ins).getOpcode().toString().equals("ADD")) { 152 assertFalse("MemoryTwoOp expected only once in first block", found); 153 found = true; 154 } 155 } 156 assertTrue("ADD with memory argument must be in the LIR", found); 157 } 158 159 /** 160 * Can't match as an add with a memory operand because the other add input is too late. 161 */ 162 public static int testAddLoadNoMatchSnippet() { 163 int v1 = volatileIntValue; 164 int v2 = intValue; 165 return v1 + (2 * v2); 166 } 167 168 @Test 169 public void testAddLoadNoMatch() { 170 compile(getResolvedJavaMethod("testAddLoadNoMatchSnippet"), null); 171 LIR lir = getLIR(); 172 boolean found = false; 173 for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) { 174 if (ins instanceof AMD64Binary.CommutativeTwoOp && ((AMD64Binary.CommutativeTwoOp) ins).getOpcode().toString().equals("ADD")) { 175 assertFalse("CommutativeTwoOp expected only once in first block", found); 176 found = true; 177 } 178 } 179 assertTrue("ADD with memory argument must not be in the LIR", found); 180 } 181 182 /** 183 * sign extension and load are in different blocks but can still be matched as a single 184 * instruction. 185 */ 186 public static long testVolatileExtensionDifferentBlocksSnippet(boolean flag) { 187 short v = shortValue; 188 if (flag) { 189 return v; 190 } 191 return 0; 192 } 193 194 @Test 195 public void testVolatileExtensionDifferentBlocks() { 196 compile(getResolvedJavaMethod("testVolatileExtensionDifferentBlocksSnippet"), null); 197 LIR lir = getLIR(); 198 boolean found = false; 199 for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) { 200 if (ins instanceof AMD64Unary.MemoryOp) { 201 ins.visitEachOutput((value, mode, flags) -> assertTrue(value.getPlatformKind().toString(), value.getPlatformKind().equals(AMD64Kind.QWORD))); 202 assertFalse("MemoryOp expected only once in first block", found); 203 found = true; 204 } 205 } 206 assertTrue("sign extending load must be in the LIR", found); 207 } 208 209 /** 210 * Add and load are not in the same block and one input is too late: can't match. 211 */ 212 public static int testAddLoadDifferentBlocksNoMatchSnippet(boolean flag) { 213 int v1 = volatileIntValue; 214 if (flag) { 215 int v2 = intValue; 216 return v1 + (2 * v2); 217 } 218 return 0; 219 } 220 221 @Test 222 public void testAddLoadDifferentBlocksNoMatch() { 223 compile(getResolvedJavaMethod("testAddLoadDifferentBlocksNoMatchSnippet"), null); 224 LIR lir = getLIR(); 225 boolean found = false; 226 for (AbstractBlockBase<?> b : lir.codeEmittingOrder()) { 227 for (LIRInstruction ins : lir.getLIRforBlock(b)) { 228 if (ins instanceof AMD64Binary.CommutativeTwoOp && ((AMD64Binary.CommutativeTwoOp) ins).getOpcode().toString().equals("ADD")) { 229 assertFalse("CommutativeTwoOp expected only once in first block", found); 230 found = true; 231 } 232 } 233 } 234 assertTrue("ADD with memory argument must not be in the LIR", found); 235 } 236 237 /** 238 * Add and load are in different blocks but can still match. 239 */ 240 public static int testAddLoadDifferentBlocksSnippet(boolean flag) { 241 int v2 = intValue; 242 int v1 = volatileIntValue; 243 if (flag) { 244 return v1 + v2; 245 } 246 return 0; 247 } 248 249 @Test 250 public void testAddLoadDifferentBlocks() { 251 compile(getResolvedJavaMethod("testAddLoadDifferentBlocksSnippet"), null); 252 LIR lir = getLIR(); 253 boolean found = false; 254 for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) { 255 if (ins instanceof AMD64Binary.MemoryTwoOp && ((AMD64Binary.MemoryTwoOp) ins).getOpcode().toString().equals("ADD")) { 256 assertFalse("MemoryTwoOp expected only once in first block", found); 257 found = true; 258 } 259 } 260 assertTrue("ADD with memory argument must be in the LIR", found); 261 } 262 263 }