# HG changeset patch # User Doug Simon # Date 1340098659 -7200 # Node ID 8d420cfd2a6f1cd3b65e166a1378e6303dc70edd # Parent 14505f3e6b4ce60bf95bba24cd300b4da7e642cf added unit tests for the Word type diff -r 14505f3e6b4c -r 8d420cfd2a6f graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java Tue Jun 19 11:37:39 2012 +0200 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.snippets; + +import static com.oracle.graal.nodes.calc.Condition.*; + +import java.lang.reflect.*; + +import org.junit.*; + +import com.oracle.graal.api.*; +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.tests.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; + +/** + * Tests for the {@link Word} type. + */ +public class WordTest extends GraalCompilerTest implements SnippetsInterface { + + private final SnippetInstaller installer; + + public WordTest() { + TargetDescription target = Graal.getRequiredCapability(GraalCompiler.class).target; + installer = new SnippetInstaller(runtime, target); + } + + @Override + protected StructuredGraph parse(Method m) { + ResolvedJavaMethod resolvedMethod = runtime.getResolvedJavaMethod(m); + return installer.makeGraph(resolvedMethod, null); + } + + @Test + public void test_arithmetic() { + long[] words = new long[] {Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE}; + for (long word : words) { + for (int addend = -1000; addend < 1000; addend++) { + test("plus_int", word, addend); + test("plus_int", word, -addend); + test("minus_int", word, addend); + test("minus_int", word, -addend); + } + for (long addend : words) { + test("plus_int", word, (int) addend); + test("minus_int", word, (int) addend); + test("plus_int", word, -((int) addend)); + test("minus_int", word, -((int) addend)); + } + } + } + + @Test + public void test_compare() { + long[] words = new long[] {Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE}; + for (long word1 : words) { + for (long word2 : words) { + for (Condition cond : new Condition[] {AE, AT, EQ, NE, BE, BT}) { + test("compare" + cond.name(), word1, word2); + test("compare" + cond.name(), word2, word1); + } + } + } + } + + @Snippet + public static long plus_int(long word, int addend) { + return Word.fromLong(word).plus(addend).toLong(); + } + + @Snippet + public static long minus_int(long word, int addend) { + return Word.fromLong(word).plus(addend).toLong(); + } + + @Snippet + public static boolean compareAE(long word1, long word2) { + return Word.fromLong(word1).cmp(Condition.AE, Word.fromLong(word2)); + } + @Snippet + public static boolean compareAT(long word1, long word2) { + return Word.fromLong(word1).cmp(Condition.AT, Word.fromLong(word2)); + } + @Snippet + public static boolean compareEQ(long word1, long word2) { + return Word.fromLong(word1).cmp(Condition.EQ, Word.fromLong(word2)); + } + @Snippet + public static boolean compareNE(long word1, long word2) { + return Word.fromLong(word1).cmp(Condition.NE, Word.fromLong(word2)); + } + @Snippet + public static boolean compareBE(long word1, long word2) { + return Word.fromLong(word1).cmp(Condition.BE, Word.fromLong(word2)); + } + @Snippet + public static boolean compareBT(long word1, long word2) { + return Word.fromLong(word1).cmp(Condition.BT, Word.fromLong(word2)); + } + +} diff -r 14505f3e6b4c -r 8d420cfd2a6f graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java Tue Jun 19 11:36:27 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java Tue Jun 19 11:37:39 2012 +0200 @@ -27,6 +27,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.snippets.Word.Operation; import com.oracle.graal.snippets.nodes.*; /** @@ -67,6 +68,9 @@ return false; } } + if (method.getAnnotation(Operation.class) != null) { + return false; + } return true; } }; diff -r 14505f3e6b4c -r 8d420cfd2a6f graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java Tue Jun 19 11:36:27 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java Tue Jun 19 11:37:39 2012 +0200 @@ -134,10 +134,10 @@ } } - private StructuredGraph makeGraph(final ResolvedJavaMethod method, final InliningPolicy policy) { + public StructuredGraph makeGraph(final ResolvedJavaMethod method, final InliningPolicy policy) { StructuredGraph graph = graphCache.get(method); if (graph == null) { - graph = buildGraph(method, policy); + graph = buildGraph(method, policy == null ? inliningPolicy(method) : policy); //System.out.println("built " + graph); graphCache.put(method, graph); } diff -r 14505f3e6b4c -r 8d420cfd2a6f graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Word.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Word.java Tue Jun 19 11:36:27 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Word.java Tue Jun 19 11:37:39 2012 +0200 @@ -26,6 +26,7 @@ import java.lang.annotation.*; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.calc.*; /** @@ -46,32 +47,83 @@ * The canonical {@link Operation} represented by a method in the {@link Word} class. */ public enum Opcode { + L2W, + I2W, + W2L, + W2I, PLUS, MINUS, COMPARE; } - private Word() { + private Word(long value) { + this.value = value; + } + + private final long value; + + @Operation(L2W) + public static Word fromLong(long value) { + return new Word(value); + } + + @Operation(I2W) + public static Word fromInt(int value) { + return new Word(value); + } + + @Operation(W2I) + public int toInt() { + return (int) value; + } + + @Operation(W2L) + public long toLong() { + return value; } @Operation(COMPARE) - public native boolean cmp(Condition condition, Word other); + public boolean cmp(Condition condition, Word other) { + long a = value; + long b = other.value; + switch (condition) { + case AE: return (a >= b) ^ ((a < 0) != (b < 0)); + case AT: return (a > b) ^ ((a < 0) != (b < 0)); + case BE: return (a <= b) ^ ((a < 0) != (b < 0)); + case BT: return (a < b) ^ ((a < 0) != (b < 0)); + case EQ: return a == b; + case NE: return a != b; + default: throw new GraalInternalError("Unexpected operation on word: " + condition); + } + } @Operation(PLUS) - public native Word plus(int addend); - - @Operation(PLUS) - public native Word plus(long addend); + public Word plus(int addend) { + return new Word(value + addend); + } @Operation(PLUS) - public native Word plus(Word addend); + public Word plus(long addend) { + return new Word(value + addend); + } - @Operation(MINUS) - public native Word minus(int addend); + @Operation(PLUS) + public Word plus(Word addend) { + return new Word(value + addend.value); + } @Operation(MINUS) - public native Word minus(long addend); + public Word minus(int addend) { + return new Word(value - addend); + } @Operation(MINUS) - public native Word minus(Word addend); + public Word minus(long addend) { + return new Word(value - addend); + } + + @Operation(MINUS) + public Word minus(Word addend) { + return new Word(value - addend.value); + } } diff -r 14505f3e6b4c -r 8d420cfd2a6f graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/WordTypeRewriterPhase.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/WordTypeRewriterPhase.java Tue Jun 19 11:36:27 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/WordTypeRewriterPhase.java Tue Jun 19 11:37:39 2012 +0200 @@ -27,7 +27,7 @@ import com.oracle.graal.compiler.phases.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.PhiNode.*; +import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.calc.ConvertNode.Op; import com.oracle.graal.nodes.extended.*; @@ -81,7 +81,7 @@ if (operation != null) { NodeInputList arguments = callTargetNode.arguments(); Invoke invoke = (Invoke) callTargetNode.usages().first(); - assert invoke != null; + assert invoke != null : callTargetNode.targetMethod(); Opcode opcode = operation.value(); switch (opcode) { @@ -99,6 +99,40 @@ invoke.intrinsify(op); break; } + + case W2I: { + assert arguments.size() == 1; + ValueNode value = arguments.last(); + ValueNode intValue = fromWordKindTo(graph, value, Kind.Int); + invoke.intrinsify(intValue); + break; + } + + case W2L: { + assert arguments.size() == 1; + ValueNode value = arguments.last(); + ValueNode longValue = fromWordKindTo(graph, value, Kind.Long); + invoke.intrinsify(longValue); + break; + } + + case L2W: { + assert arguments.size() == 1; + ValueNode value = arguments.last(); + assert value.kind() == Kind.Long; + ValueNode wordValue = asWordKind(graph, value); + invoke.intrinsify(wordValue); + break; + } + + case I2W: { + assert arguments.size() == 1; + ValueNode value = arguments.last(); + assert value.kind() == Kind.Int; + invoke.intrinsify(asWordKind(graph, value)); + break; + } + default: { throw new GraalInternalError("Unknown opcode: %s", opcode); } @@ -111,7 +145,7 @@ * Creates comparison node for a given condition and two input values. */ private ValueNode compare(Condition condition, StructuredGraph graph, ValueNode left, ValueNode right) { - assert condition.isUnsigned(); + assert condition.isUnsigned() || condition == Condition.EQ || condition == Condition.NE : condition; assert left.kind() == wordKind; assert right.kind() == wordKind; @@ -158,6 +192,21 @@ return value; } + private static ValueNode fromWordKindTo(StructuredGraph graph, ValueNode value, Kind to) { + Kind from = value.kind(); + if (from != to) { + Op op; + if (from.isLong()) { + op = Op.L2I; + } else { + assert from.isInt(); + op = Op.I2L; + } + return graph.unique(new ConvertNode(op, value)); + } + return value; + } + public boolean isWord(ValueNode node) { return isWord(node.stamp().declaredType()); } diff -r 14505f3e6b4c -r 8d420cfd2a6f graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java Tue Jun 19 11:36:27 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java Tue Jun 19 11:37:39 2012 +0200 @@ -67,7 +67,7 @@ } final ResolvedJavaMethod riMethod = runtime.getResolvedJavaMethod(method); - InstalledCode compiledMethod = compile(riMethod, graph); + InstalledCode compiledMethod = getCode(riMethod, graph); try { Object result = compiledMethod.execute("1", "2", "3"); Assert.assertEquals("1-2-3", result); @@ -81,7 +81,7 @@ Method method = getMethod("testMethod"); final StructuredGraph graph = parse(method); final ResolvedJavaMethod riMethod = runtime.getResolvedJavaMethod(method); - InstalledCode compiledMethod = compile(riMethod, graph); + InstalledCode compiledMethod = getCode(riMethod, graph); try { Object result = compiledMethod.executeVarargs("1", "2", "3"); Assert.assertEquals("1 2 3", result); @@ -95,7 +95,7 @@ Method method = getMethod("testMethodVirtual"); final StructuredGraph graph = parse(method); final ResolvedJavaMethod riMethod = runtime.getResolvedJavaMethod(method); - InstalledCode compiledMethod = compile(riMethod, graph); + InstalledCode compiledMethod = getCode(riMethod, graph); try { f1 = "0"; Object result = compiledMethod.executeVarargs(this, "1", "2", "3"); @@ -123,7 +123,7 @@ } } - InstalledCode compiledMethod = compile(riMethod, graph); + InstalledCode compiledMethod = getCode(riMethod, graph); final CompilableObject compilableObject = new CompilableObjectImpl(0); Object result; diff -r 14505f3e6b4c -r 8d420cfd2a6f graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraalCompilerTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraalCompilerTest.java Tue Jun 19 11:36:27 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraalCompilerTest.java Tue Jun 19 11:37:39 2012 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.compiler.tests; import java.lang.reflect.*; +import java.util.*; import java.util.concurrent.*; import junit.framework.*; @@ -163,8 +164,7 @@ } catch (Exception e) { throw new RuntimeException(e); } - InstalledCode compiledMethod = compile(runtime.getResolvedJavaMethod(method), parse(method)); - compiledMethod.method(); + InstalledCode compiledMethod = getCode(runtime.getResolvedJavaMethod(method), parse(method)); if (exception != null) { try { @@ -179,13 +179,35 @@ } } - protected InstalledCode compile(final ResolvedJavaMethod method, final StructuredGraph graph) { - return Debug.scope("Compiling", new DebugDumpScope(String.valueOf(compilationId++), true), new Callable() { + private Map cache = new HashMap<>(); + + /** + * Gets installed code for a given method and graph, compiling it first if necessary. + */ + protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph) { + return getCode(method, graph, false); + } + + /** + * Gets installed code for a given method and graph, compiling it first if necessary. + * + * @param forceCompile specifies whether to ignore any previous code cached for the (method, key) pair + */ + protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph, boolean forceCompile) { + if (!forceCompile) { + InstalledCode cached = cache.get(method); + if (cached != null && cached.isValid()) { + return cached; + } + } + InstalledCode installedCode = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(compilationId++), true), new Callable() { public InstalledCode call() throws Exception { CompilationResult targetMethod = runtime.compile(method, graph); return addMethod(method, targetMethod); } }); + cache.put(method, installedCode); + return installedCode; } protected InstalledCode addMethod(final ResolvedJavaMethod method, final CompilationResult tm) { diff -r 14505f3e6b4c -r 8d420cfd2a6f graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeCheckTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeCheckTest.java Tue Jun 19 11:36:27 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeCheckTest.java Tue Jun 19 11:37:39 2012 +0200 @@ -36,11 +36,13 @@ protected JavaTypeProfile currentProfile; @Override - protected InstalledCode compile(final ResolvedJavaMethod method, final StructuredGraph graph) { + protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph) { + boolean forceCompile = false; if (currentProfile != null) { replaceProfile(graph, currentProfile); + forceCompile = true; } - return super.compile(method, graph); + return super.getCode(method, graph, forceCompile); } protected JavaTypeProfile profile(Class... types) {