EmitDeoptimize, EmitForignCall "createOutOfBoundsException"

Deneau, Tom tom.deneau at amd.com
Wed Jul 3 10:15:15 PDT 2013

I noticed that if I have the same structure where the compiled method
inlines a leaf method but the leaf method is small enough (I used
the IntSquaredTest), then the resulting LIR that is handed to the backend
has only deopt nodes, no ForeignCall nodes.

Looking at the igv graphs for the "smaller" leaf node inline,
I can see that right after inlining the ForeignCall
nodes (to CreateOutOfBoundsException) are still there, 
but they become FixedGuard nodes after the  DeadCodeElimination phase.
And then later, after Guard Lowering phase, they become deopt nodes.

Whereas for the "larger" leaf node inline case, the ForeignCall nodes
never become FixedGuard nodes.  Not sure why they are treated differently
in this case.

-- Tom

-----Original Message-----
From: graal-dev-bounces at openjdk.java.net [mailto:graal-dev-bounces at openjdk.java.net] On Behalf Of Deneau, Tom
Sent: Wednesday, July 03, 2013 10:42 AM
To: Gilles Duboscq
Cc: graal-dev at openjdk.java.net
Subject: RE: EmitDeoptimize, EmitForignCall "createOutOfBoundsException"

Gilles --

Asking my question from another angle, if we do have to consume the foreignCall to createOutOfBoundsException and effectively ignore it, is there something we can do from our side that will not upset the control flow graph and  register allocation invariants of the original LIR?

-- Tom

From: Deneau, Tom
Sent: Wednesday, July 03, 2013 9:25 AM
To: 'Gilles Duboscq'
Cc: graal-dev at openjdk.java.net
Subject: RE: EmitDeoptimize, EmitForignCall "createOutOfBoundsException"

Gilles --

It is strange that profiling would show that out of bounds exceptions were thrown on that path, I am quite sure that such exceptions are not being thrown when this code is run from the java side.  I also don't understand how profiling would show such exceptions in case #2 but not in case #1

case #1, compile this "run" method

    public static void run(float[] inxyz, float[] outxyz, float[] invxyz, float[] outvxyz, int gid) {
         .. fairly large leaf routine, over 300 nodes

case #2, compile this "run" method

    public static void run(float[] inxyz, float[] outxyz, float[] invxyz, float[] outvxyz, int gid) {
          updateBody(inxyz, outxyz, invxyz, outvxyz, gid);

    public static void updateBody(float[] inxyz, float[] outxyz, float[] invxyz, float[] outvxyz, int gid) {
           .. same contents as "run" method in case #1

Your answer about the register allocation invariants with foreign call makes since.  So since we cannot yet handle the foreign call for this target, is there a flag that will force the LIR to emit a Deoptimization node (which we are able to effectively ignore) rather than a foreign call node when the purpose of the foreign call node is to create an OutOfBounds exception?

-- Tom

From: gilwooden at gmail.com [mailto:gilwooden at gmail.com] On Behalf Of Gilles Duboscq
Sent: Wednesday, July 03, 2013 3:51 AM
To: Deneau, Tom
Cc: graal-dev at openjdk.java.net
Subject: Re: EmitDeoptimize, EmitForignCall "createOutOfBoundsException"

For your first question, the profile seems to be the key: this path through the "create..." foreign call should only appear if profiling shows that array out of bounds exceptions are actually thrown at this position.
In this case the exception handling is done in the compiled code: it will create the exception object with that foreign call and the execution will be diverted to any  catch handler that the compiler could find.

Otherwise, if profile shows that no exception is thrown, the compiler assumes it can leave the exception handling out. A deoptimization will be used to go back to the interpreter if that assumption proved to be incorrect.

A deoptimization is – like a return – a control flow sink, it ends the execution of the current compilation unit. The foreign call on the other end is not a control flow sink.
If you replace a foreign call with a return during LIR generation I can see how later stages such as register allocation can get confused.
In general, it is not a good idea to modify the control flow graph during LIR generation, many of invariants of the algorithms working on the LIR will fail.

When compiling for such a target I suppose that you want to stick to deoptimization to handle cases that are not supported by this execution environment.
On 2 Jul 2013 20:03, "Tom Deneau" <tom.deneau at amd.com<mailto:tom.deneau at amd.com>> wrote:
Here is the background for my visualizer question:

We have a junit test (part of the webrev) called StaticNBodyTest and the HSAIL backend is able
to compile the fairly large run method without problem.

Now to test inlining decisions, I moved the logic to a separate updateBody method, and had the
run method (the target of the compile) call the updateBody method.  By default, updateBody has too
many nodes to be inlined, but I raised the MaximumInliningSize and now graal does indeed inline it.

With the inlining completed, the HSAILLirGenerator is now passed several emitForeignCall requests
with the target being "createOutOfBoundsException".  Yet in the original StaticNBodyTest (same code,
just not behind a second layer of method call), there were no emitForeignCall requests.
Instead there were emitDeoptimize requests for the path taken when an array index was out of bounds.

Question 1: Why would there be emitDeoptimize in one case, and emitForeignCall after inlining?

As a followup question...

We have not decided how to handle exceptions yet in the HSAIL backend, so the emitDeoptimize request
is turned into a request to return early from the HSAIL kernel.   With this strategy, code generation

However, if I use similar logic with the emitForeignCall request, i.e. just generate a return,
or even just ignore the ForeignCall request completely, I hit the following error later in the codegen:

java.lang.AssertionError: using fixed register that is not defined in this block
        at com.oracle.graal.compiler.alloc.LinearScan.verifyInput(LinearScan.java:791)

Question 2: Why would this register assertion occur when emitForeignCall is replaced by a return, but not when emitDeoptimize
is similarly replaced by a return?

-- Tom Deneau

-----Original Message-----
From: graal-dev-bounces at openjdk.java.net<mailto:graal-dev-bounces at openjdk.java.net> [mailto:graal-dev-bounces at openjdk.java.net<mailto:graal-dev-bounces at openjdk.java.net>] On Behalf Of Deneau, Tom
Sent: Tuesday, July 02, 2013 11:53 AM
To: graal-dev at openjdk.java.net<mailto:graal-dev at openjdk.java.net>
Subject: mx igv or mx gv commands

When I try to use
   mx igv &

as described on the wiki page, I get the splash screen for the visualize but then it dies.
Similarly with mx gv &

Is there some other command that must be run first before using these?

-- Tom

More information about the graal-dev mailing list