<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Paul,<br>
<br>
This looks reasonable.<br>
<br>
Debugging this my end yesterday, I concluded that where the method is supposed to return a value and I see a return without a value, it should be a huge hint to my C99 code gen that this return is not reachable and so my C99 code gen can just omit the return. <br>
<br>
In the case where the return is void I would indeed emit an unnecessary 'return;' which thankfully CUDA and OpenCL just accepts as noise.<br>
<br>
I was about to make this mildy hacky change this morning, but now will await the fix you suggest, as I do think tagging this with an unreachable Op rather than return Op would be far more useful in the general case.<br>
<br>
BTW outlook tagged the email below as in 'Slovak' 😉<br>
<br>
Gary<br>
<br>
<br>
<br>
</div>
<div id="appendonsend"></div>
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> babylon-dev <babylon-dev-retn@openjdk.org> on behalf of Paul Sandoz <paul.sandoz@oracle.com><br>
<b>Sent:</b> Thursday, October 17, 2024 12:16 AM<br>
<b>To:</b> babylon-dev@openjdk.org <babylon-dev@openjdk.org><br>
<b>Subject:</b> Re: Unreachability</font>
<div> </div>
</div>
<div class="BodyFragment"><font size="2"><span style="font-size:11pt;">
<div class="PlainText">Here’s a possible fix:<br>
<br>
CoreOp.FuncOp scanMethod() {<br>
scan(body);<br>
appendReturnOrUnreachable(body);<br>
CoreOp.FuncOp func = CoreOp.func(name.toString(), stack.body);<br>
func.setLocation(generateLocation(currentNode, true));<br>
return func;<br>
}<br>
<br>
private <O extends Op & Op.Terminating> void appendReturnOrUnreachable(JCTree body) {<br>
// Append only if an existing terminating operation is not present<br>
if (lastOp == null || !(lastOp instanceof Op.Terminating)) {<br>
if (isReachable(body)) {<br>
append(CoreOp._return());<br>
} else {<br>
append(CoreOp.unreachable());<br>
}<br>
}<br>
}<br>
<br>
boolean isReachable(JCTree node) {<br>
return flow.aliveAfter(typeEnvs.get(currentClassSym), node, make);<br>
}<br>
<br>
Paul.<br>
<br>
> On Oct 16, 2024, at 1:18 PM, Paul Sandoz <paul.sandoz@oracle.com> wrote:<br>
> <br>
> Hi,<br>
> <br>
> Gary encountered an issue when transforming say:<br>
> <br>
> @CodeReflection<br>
> public static float f(float input) {<br>
> if (input >= 0f) {<br>
> return 1f;<br>
> } else {<br>
> return 0f;<br>
> }<br>
> // Unreachable<br>
> }<br>
> <br>
> Compiler produced model:<br>
> <br>
> func @"f" @loc="10:5:..." (%0 : float)float -> {<br>
> %1 : Var<float> = var %0 @"input" @loc="10:5";<br>
> java.if @loc="13:9"<br>
> ()boolean -> {<br>
> %2 : float = var.load %1 @loc="13:13";<br>
> %3 : float = constant @"0.0" @loc="13:22";<br>
> %4 : boolean = ge %2 %3 @loc="13:13";<br>
> yield %4 @loc="13:9";<br>
> }<br>
> ()void -> {<br>
> %5 : float = constant @"1.0" @loc="14:20";<br>
> return %5 @loc="14:13";<br>
> }<br>
> ()void -> {<br>
> %6 : float = constant @"0.0" @loc="16:20";<br>
> return %6 @loc="16:13";<br>
> };<br>
> return @loc="10:5";<br>
> };<br>
> <br>
> Lowered model:<br>
> <br>
> func @"f" @loc="10:5:..." (%0 : float)float -> {<br>
> %1 : Var<float> = var %0 @"input" @loc="10:5";<br>
> %2 : float = var.load %1 @loc="13:13";<br>
> %3 : float = constant @"0.0" @loc="13:22";<br>
> %4 : boolean = ge %2 %3 @loc="13:13";<br>
> cbranch %4 ^block_1 ^block_2;<br>
> <br>
> ^block_1:<br>
> %5 : float = constant @"1.0" @loc="14:20";<br>
> return %5 @loc="14:13";<br>
> <br>
> ^block_2:<br>
> %6 : float = constant @"0.0" @loc="16:20";<br>
> return %6 @loc="16:13";<br>
> <br>
> ^block_3:<br>
> return @loc="10:5";<br>
> };<br>
> <br>
> <br>
> The compiler produced model is incorrect placing a return operation when it should be an unreachable operation.<br>
> <br>
> There are some reminders in ReflectMethods:<br>
> <br>
> CoreOp.FuncOp scanMethod() {<br>
> scan(body);<br>
> // @@@ Check if unreachable<br>
> appendTerminating(CoreOp::_return);<br>
> CoreOp.FuncOp func = CoreOp.func(name.toString(), stack.body);<br>
> func.setLocation(generateLocation(currentNode, true));<br>
> return func;<br>
> }<br>
> <br>
> We need to determine if the last statement yields control or not. (It’s easy to see if we lower, as ^block_3 is never referenced.)<br>
> <br>
> In this case we can know because there is no return value in scope, but generally we cannot rely upon that.<br>
> <br>
> The compiler already checks this, I believe in Flow.AliveAnalyzer. However, it does not add additional information to the attributed tree - it does not need to.<br>
> <br>
> Can we reuse the method Flow.aliveAfter? Although I don’t know how to get access to an instance of Env<AttrContext>. Do we get it from TypeEnvs?<br>
> <br>
> Paul.<br>
<br>
</div>
</span></font></div>
</body>
</html>