compiled leaf method vs. inlined method bounds check
Gilles Duboscq
duboscq at ssw.jku.at
Thu Nov 21 03:27:03 PST 2013
Hello Tom,
sorry for the delayed answer.
I did the tests and i can not reproduce the behaviour you are seeing if no
exception is ever thrown.
However i can easily reproduce it if the first method (the one containing
the array accesses) has already thrown an exception while the second one
(the one containing the call) has never seen an exception flow through the
call.
In this case the second method assumes no exception can never flow through
the call but when it inline the call, it sees that it actually needs to
handle exceptions, in this case you get that
NotCompiledExceptionHandler reason.
I used this to test:
public class ArrayTest extends JTTTest {
static int[] array = {1, 2, 3};
@Test
public void test0() throws Throwable {
run(new int[3], array, array, 0);
runTest("callRun", new int[3], array, array, 0);
}
@Test
public void test1() throws Throwable {
run(new int[3], array, array, 3);
runTest("callRun", new int[3], array, array, 0);
}
@Test
public void test2() throws Throwable {
callRun(new int[3], array, array, 3);
runTest("callRun", new int[3], array, array, 0);
}
public static void run(int[] out, int[] ina, int[] inb, int gid) {
out[gid] = ina[gid] + inb[gid];
}
public static void callRun(int[] out, int[] ina, int[] inb, int gid) {
run(out, ina, inb, gid);
}
}
In the first case (test0) i get the inlined call an
the BoundsCheckException reason.
In the second case (test1) i get the inlined call and the
NotCompiledExceptionHandler reason.
In the thrid case (test2) i get the full exception handling.
Note that you need to run these separately if you don't want profile
pollution.
-Gilles
On Wed, Nov 13, 2013 at 1:22 AM, Tom Deneau <tom.deneau at amd.com> wrote:
> Gilles --
>
>
>
> OK, we have a simple existing test in
> com.oracle.graal.compiler.hsail.test.IntAddTest which adds ints from two
> arrays putting the result in a third output array
>
> public static void run(int[] out, int[] ina, int[] inb, int gid) {
>
> out[gid] = ina[gid] + inb[gid];
>
> }
>
>
>
> Here is the hsail code:. (Note that we don't really handle the
> DeoptimizeNode but just print a comment based on the reason).
>
>
>
> version 0:95: $full : $large;
>
> // static method HotSpotMethod<IntAddTest.run(int[], int[], int[],
> int)>
>
> kernel &run (
>
> kernarg_u64 %_arg0,
>
> kernarg_u64 %_arg1,
>
> kernarg_u64 %_arg2
>
> ) {
>
> ld_kernarg_u64 $d0, [%_arg0];
>
> ld_kernarg_u64 $d1, [%_arg1];
>
> ld_kernarg_u64 $d2, [%_arg2];
>
> workitemabsid_u32 $s0, 0;
>
>
>
> @L0:
>
> ld_global_s32 $s1, [$d0 + 12];
>
> cmp_ge_b1_u32 $c0, $s0, $s1;
>
> cbr $c0, @L7;
>
> @L1:
>
> ld_global_s32 $s1, [$d2 + 12];
>
> cmp_ge_b1_u32 $c0, $s0, $s1;
>
> cbr $c0, @L7;
>
> @L2:
>
> ld_global_s32 $s1, [$d1 + 12];
>
> cmp_ge_b1_u32 $c0, $s0, $s1;
>
> cbr $c0, @L7;
>
> @L3:
>
> cvt_s64_s32 $d3, $s0;
>
> mul_s64 $d3, $d3, 4;
>
> add_u64 $d1, $d1, $d3;
>
> ld_global_s32 $s1, [$d1 + 16];
>
> cvt_s64_s32 $d1, $s0;
>
> mul_s64 $d1, $d1, 4;
>
> add_u64 $d2, $d2, $d1;
>
> ld_global_s32 $s2, [$d2 + 16];
>
> add_s32 $s2, $s2, $s1;
>
> cvt_s64_s32 $d1, $s0;
>
> mul_s64 $d1, $d1, 4;
>
> add_u64 $d0, $d0, $d1;
>
> st_global_s32 $s2, [$d0 + 16];
>
> ret;
>
> @L7:
>
> // Deoptimization for BoundsCheckException would occur here
>
> ret;
>
> };
>
>
>
>
>
> Then I made a new test where the run method just basically called the
> original IntAddTest.run
>
> public static void run(int[] out, int[] ina, int[] inb, int gid) {
>
> IntAddTest.run(out, ina, inb, gid);
>
> }
>
>
>
> We compile with InlineEverything set. We got this almost identical hsail
> code except for the deoptimization reason. (In this case, there is no call
> to createOutOfBoundsException but I have seen it in larger test cases).
> Note that in either case, no exceptions would have occurred when profiling.
>
>
>
> version 0:95: $full : $large;
>
> // static method HotSpotMethod<IntAddInlineTest.run(int[], int[], int[],
> int)>
>
> kernel &run (
>
> kernarg_u64 %_arg0,
>
> kernarg_u64 %_arg1,
>
> kernarg_u64 %_arg2
>
> ) {
>
> ld_kernarg_u64 $d0, [%_arg0];
>
> ld_kernarg_u64 $d1, [%_arg1];
>
> ld_kernarg_u64 $d2, [%_arg2];
>
> workitemabsid_u32 $s0, 0;
>
>
>
> @L0:
>
> ld_global_s32 $s1, [$d0 + 12];
>
> cmp_ge_b1_u32 $c0, $s0, $s1;
>
> cbr $c0, @L7;
>
> @L1:
>
> ld_global_s32 $s1, [$d2 + 12];
>
> cmp_ge_b1_u32 $c0, $s0, $s1;
>
> cbr $c0, @L7;
>
> @L2:
>
> ld_global_s32 $s1, [$d1 + 12];
>
> cmp_ge_b1_u32 $c0, $s0, $s1;
>
> cbr $c0, @L7;
>
> @L3:
>
> cvt_s64_s32 $d3, $s0;
>
> mul_s64 $d3, $d3, 4;
>
> add_u64 $d1, $d1, $d3;
>
> ld_global_s32 $s1, [$d1 + 16];
>
> cvt_s64_s32 $d1, $s0;
>
> mul_s64 $d1, $d1, 4;
>
> add_u64 $d2, $d2, $d1;
>
> ld_global_s32 $s2, [$d2 + 16];
>
> add_s32 $s2, $s2, $s1;
>
> cvt_s64_s32 $d1, $s0;
>
> mul_s64 $d1, $d1, 4;
>
> add_u64 $d0, $d0, $d1;
>
> st_global_s32 $s2, [$d0 + 16];
>
> ret;
>
> @L7:
>
> // Deoptimization for NotCompiledExceptionHandler would
> occur here
>
> ret;
>
> };
>
>
>
>
>
> *From:* gilwooden at gmail.com [mailto:gilwooden at gmail.com] *On Behalf Of *Gilles
> Duboscq
> *Sent:* Tuesday, November 12, 2013 5:56 PM
> *To:* Deneau, Tom
> *Cc:* graal-dev at openjdk.java.net
> *Subject:* Re: compiled leaf method vs. inlined method bounds check
>
>
>
> Can you maybe show us the snippets you used and how you ran them?
>
> The second scenario you describe usually happen if an
> ArrayIndexOutOfBoundsException has already been thrown at the array access
> you're looking at.
>
> When compiling an array access, Graal will look at the profile and if it
> shows that exceptions are thrown there, it will compile in the exception
> branch (in your case the exception branch ends up into an other deopt for
> some reason). If profiling shows no exception has been thrown there, it
> will leave out the exception branch and will only place a which deoptimizes
> in case an exception needs to be thrown.
>
>
>
> This should have nothing to do with inlining. When doings tests about
> that, be carefull not to pollute the profile for the second test with the
> first one.
>
> You can change the bahviour of graal reagrding these things using
> the UseExceptionProbabilityForOperations flag.
>
>
>
> -Gilles
>
>
>
> On Tue, Nov 12, 2013 at 11:49 PM, Tom Deneau <tom.deneau at amd.com> wrote:
>
> I've noticed that if the graph I am compiling is simply a leaf method
> which accesses an array, the target of a failing bounds check is a
> DeoptimizeNode with reason=BoundsCheckException, action=InvalidateReprofile
>
> But if the method that is accessing the array is being inlined into
> another method, the target of the failing bounds check is a ForeignCall to
> createOutOfBoundsException followed by a branch to a DeoptimizeNode with
> reason=NotCompiledExceptionHandler, action=InvalidateRecompile.
>
> Can someone explain this difference?
>
> -- Tom
>
>
>
More information about the graal-dev
mailing list