buggy behavior in AMD64NodeLIRBuilder.emitCompareBranchMemory

Yudi Zheng yudi.zheng at usi.ch
Thu May 15 06:11:14 UTC 2014


The simplified test case I sent yesterday is the following:

public class TailDuplicationTest {

interface I {
}

enum P implements I {
A, B
}

final static I CONST_I = new I() {
};

public static I foo(int i) {
if (i < 32) {
return P.A;
} else if (i < 64) {
return P.B;
} else {
return CONST_I;
}
}

public int bar(int i) {
P instance = (P) foo(i);

if (instance != P.B) {
return 0;
}

return 1;
}

public static void main(String[] args) {
TailDuplicationTest t = new TailDuplicationTest();

for (int i = 0; i < 100000; i++) {
foo(i % 128);
t.bar(i % 64);
}
}

}

Look at the graph of TailDuplicationTest.bar, the "return 1" branch is dropped between LoopFullUnroll and TailDuplication.
It is caused by a stamp evaluation which compares an illegal "a!# -" with "a!# LTailDuplicationTest$P;"
The illegal "a!# -" is generated by ValuePhiNode.inferPhiStamp…

I inserted graph dumping at TailDuplicationPhase#328 and ObjectEqualsNode#64. Please have a look at the stamp changes
on "48 ValuePhi()" (hopefully the same ID),

diff -r 55977f9fa56f graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Sun May 11 22:00:06 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Thu May 15 08:07:39 2014 +0200
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.meta.ProfilingInfo.*;
 import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
@@ -62,6 +63,10 @@
         if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
             return TriState.TRUE;
         } else if (forX.stamp().alwaysDistinct(forY.stamp())) {
+            if ("bar".equals(graph().method().getName())) {
+                Debug.dump(graph(), "During canonicalizer phase in tail duplication, ObjectEqualsNode#64");
+            }
+
             return TriState.FALSE;
         } else {
             return super.evaluate(constantReflection, forX, forY);
@@ -119,7 +124,7 @@
                 /*
                  * One of the two objects has identity, the other doesn't. In code, this looks like
                  * "Integer.valueOf(a) == new Integer(b)", which is always false.
-                 *
+                 *
                  * In other words: an object created via valueOf can never be equal to one created
                  * by new in the same compilation unit.
                  */
diff -r 55977f9fa56f graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Sun May 11 22:00:06 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Thu May 15 08:07:39 2014 +0200
@@ -326,6 +326,9 @@
                     phi.setMerge(mergeAfter);
                 }
             }
+            if ("bar".equals(graph.method().getName())) {
+                Debug.dump(graph, "Before canonicalizer phase in tail duplication, TailDuplicationPhase#328");
+            }
             canonicalizer.applyIncremental(graph, phaseContext, startMark);
             Debug.dump(graph, "After tail duplication at %s", merge);
         }


- Yudi

On 15 May 2014, at 06:12, Tom Rodriguez <tom.rodriguez at oracle.com<mailto:tom.rodriguez at oracle.com>> wrote:

I think this is actually a bug in tail duplication.  I’ve been chasing my tail a bit on this because the code that reports the error is only compiled when exercising the matching code, so I assumed they were causally connected.  I just added logic that allows the matching logic to run but never installs the match result, so the code is exercised but doesn’t actually change code generation and it still shows up.  Looking at the graph I can see if the isInt guard disappear during tail duplication which causes the problem I’m seeing.  https://lafo.ssw.uni-linz.ac.at/jira/browse/GRAAL-791 has a patch that makes it easy to reproduce.  Hopefully Lukas can get to the bottom of it.

tom

On May 14, 2014, at 11:01 AM, Tom Rodriguez <tom.rodriguez at oracle.com<mailto:tom.rodriguez at oracle.com>> wrote:

Thanks for the test case.  I’ve been narrowing it down in between a few other things but I was seeing an issue with a mirrored unsigned compare.  It generates bad code in the compiler itself and then fails much later.  It’s possible there are multiple things going on.  Anyway, I hope to have it resolved today.

tom

On May 14, 2014, at 10:56 AM, Yudi Zheng <yudi.zheng at usi.ch<mailto:yudi.zheng at usi.ch>> wrote:

In case you might need it, please find attached the simplified test case.
During the TailDuplicationPhase when compiling TailDuplicatoinTest.bar,
some ObjectEqualsNode is evaluated to false..
(com.oracle.graal.nodes.calc.ObjectEqualsNode.java#64)

- Yudi


On 13 May 2014, at 00:40, Tom Rodriguez <tom.rodriguez at oracle.com<mailto:tom.rodriguez at oracle.com><mailto:tom.rodriguez at oracle.com>> wrote:

Thanks for the report.  I’m looking into it.

tom

On May 12, 2014, at 1:10 PM, Yudi Zheng <yudi.zheng at usi.ch<mailto:yudi.zheng at usi.ch><mailto:yudi.zheng at usi.ch>> wrote:

Hi,

1. A minor problem is that the default TypeProfileWidth is 2, resulting in lots of megamorphic-inlining with a probability of 60~70% in many cases,
instead of polymorphic-inlining.

2. When running with -XX:TypeProfileWidth=8, I observed buggy behavior:

mx vm -XX:+BootstrapGraal -XX:TypeProfileWidth=8 -version
Bootstrapping Graal.......................com.oracle.graal.compiler.common.GraalInternalError: should not reach here
at lir instruction: B192 at 1350 LCMP (address: [rax|j + 24], y: long[33286881400|0x7c00d8078]{HotSpotType<Lcom/oracle/graal/nodes/DeoptimizingNode$DeoptBefore;, resolved>}) kind: long
[B0, B2, B3, B5, B6, B8, B416, B419, B9, B11, B12, B14, B16, B17, B19, B21, B413, B23, B25, B26, B28, B29, B31, B409, B412, B32, B33, B35, B36, B38, B39, B41, B42, B44, B45, B47, B49, B50, B52, B54, B53, B55, B56, B57, B59, B61, B63, B65, B66, B67, B69, B70, B72, B74, B77, B79, B80, B94, B96, B98, B99, B101, B102, B103, B104, B107, B108, B109, B110, B113, B114, B115, B117, B118, B120, B122, B125, B127, B128, B129, B143, B145, B147, B148, B160, B126, B119, B149, B116, B130, B132, B153, B133, B136, B138, B139, B141, B142, B137, B140, B150, B134, B168, B105, B166, B171, B180, B181, B183, B186, B188, B190, B192, B194, B196, B198, B200, B197, B161, B170, B179, B177, B178, B184, B403, B78, B193, B202, B203, B204, B209, B211, B212, B214, B399, B401, B215, B216, B218, B220, B222, B397, B71, B208, B205, B206, B100, B195, B201, B187, B189, B68, B191, B199, B219, B224, B226, B228, B229, B231, B233, B394, B395, B221, B223, B82, B84, B173, B174, B154, B155, B51, B48, B232, B235, B239, B393, B236, B238, B234, B85, B87, B89, B90, B92, B93, B88, B240, B242, B284, B286, B288, B289, B291, B294, B296, B297, B299, B300, B302, B304, B307, B308, B310, B311, B313, B315, B317, B318, B320, B322, B323, B325, B326, B327, B343, B345, B346, B348, B349, B351, B354, B356, B357, B358, B360, B362, B364, B365, B367, B369, B372, B368, B373, B83, B371, B46, B352, B237, B287, B316, B330, B332, B333, B335, B336, B337, B244, B246, B247, B249, B250, B252, B254, B257, B258, B260, B261, B263, B265, B267, B268, B270, B273, B275, B276, B370, B266, B207, B285, B314, B264, B91, B355, B295, B245, B339, B384, B301, B306, B251, B256, B390, B391, B281, B283, B167, B282, B347, B382, B344, B30, B27, B378, B379, B175, B385, B388, B324, B386, B34, B407, B259, B280, B402, B312, B387, B309, B62, B389, B24, B410, B210, B392, B165, B230, B278, B159, B415, B396, B135, B404, B262, B169, B157, B10, B381, B15, B331, B376, B277, B405, B414, B37, B1, B213, B398, B417, B279, B418, B408, B400, B176, B338, B58, B40, B151, B274, B411, B380, B375, B334, B7, B340, B64, B4, B377, B406, B60, B13, B172, B163, B106, B86, B217, B18, B112, B383]
at com.oracle.graal.compiler.common.GraalInternalError.shouldNotReachHere(GraalInternalError.java:44)
at com.oracle.graal.lir.amd64.AMD64Compare$CompareMemoryOp.emitMemAccess(AMD64Compare.java:129)
at com.oracle.graal.lir.amd64.AMD64Move$MemOp.emitCode(AMD64Move.java:129)
at com.oracle.graal.lir.amd64.AMD64LIRInstruction.emitCode(AMD64LIRInstruction.java:36)
at com.oracle.graal.lir.asm.CompilationResultBuilder.emitOp(CompilationResultBuilder.java:350)
at com.oracle.graal.lir.asm.CompilationResultBuilder.emitBlock(CompilationResultBuilder.java:341)
at com.oracle.graal.lir.asm.CompilationResultBuilder.emit(CompilationResultBuilder.java:323)
at com.oracle.graal.hotspot.amd64.AMD64HotSpotBackend.emitCodeBody(AMD64HotSpotBackend.java:301)
at com.oracle.graal.hotspot.amd64.AMD64HotSpotBackend.emitCode(AMD64HotSpotBackend.java:254)
at com.oracle.graal.compiler.GraalCompiler.emitCode(GraalCompiler.java:288)
at com.oracle.graal.compiler.GraalCompiler.emitBackEnd(GraalCompiler.java:200)
at com.oracle.graal.compiler.GraalCompiler.compileGraph(GraalCompiler.java:141)
at com.oracle.graal.hotspot.CompilationTask.runCompilation(CompilationTask.java:302)
at com.oracle.graal.hotspot.CompilationTask.run(CompilationTask.java:159)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
at com.oracle.graal.compiler.CompilerThread.run(CompilerThread.java:48)


The potential bug can be tracked in com.oracle.graal.compiler.amd64.AMD64NodeLIRBuilder.emitCompareBranchMemory
(-G:Dump= -G:MethodFilter=com.oracle.graal.compiler.amd64.AMD64NodeLIRBuilder.emitCompareBranchMemory),
and can be bypassed either by not inlining com.oracle.graal.compiler.amd64.AMD64NodeLIRBuilder.getMemoryKind,
or by skipping the TailDuplicationPhase.

I guess that the TailDuplicationPhase dropped some of the IfNode. Could be verified using the following code:

protected ComplexMatchResult emitCompareBranchMemory(IfNode ifNode, CompareNode compare, ValueNode value, Access access) {
    Condition cond = compare.condition();
    Kind kind = getMemoryKind(access);

    if (kind != Kind.Long) {
        notInlinedMethodPlaceHolder(kind);
    }

After tail duplication at some merge node, the IfNode<if (kind != Kind.Long)> disappeared..

- Yudi




<TailDuplicationTest.java>





More information about the graal-dev mailing list