Unreachability
Paul Sandoz
paul.sandoz at oracle.com
Wed Oct 16 23:16:25 UTC 2024
Here’s a possible fix:
CoreOp.FuncOp scanMethod() {
scan(body);
appendReturnOrUnreachable(body);
CoreOp.FuncOp func = CoreOp.func(name.toString(), stack.body);
func.setLocation(generateLocation(currentNode, true));
return func;
}
private <O extends Op & Op.Terminating> void appendReturnOrUnreachable(JCTree body) {
// Append only if an existing terminating operation is not present
if (lastOp == null || !(lastOp instanceof Op.Terminating)) {
if (isReachable(body)) {
append(CoreOp._return());
} else {
append(CoreOp.unreachable());
}
}
}
boolean isReachable(JCTree node) {
return flow.aliveAfter(typeEnvs.get(currentClassSym), node, make);
}
Paul.
> On Oct 16, 2024, at 1:18 PM, Paul Sandoz <paul.sandoz at oracle.com> wrote:
>
> Hi,
>
> Gary encountered an issue when transforming say:
>
> @CodeReflection
> public static float f(float input) {
> if (input >= 0f) {
> return 1f;
> } else {
> return 0f;
> }
> // Unreachable
> }
>
> Compiler produced model:
>
> func @"f" @loc="10:5:..." (%0 : float)float -> {
> %1 : Var<float> = var %0 @"input" @loc="10:5";
> java.if @loc="13:9"
> ()boolean -> {
> %2 : float = var.load %1 @loc="13:13";
> %3 : float = constant @"0.0" @loc="13:22";
> %4 : boolean = ge %2 %3 @loc="13:13";
> yield %4 @loc="13:9";
> }
> ()void -> {
> %5 : float = constant @"1.0" @loc="14:20";
> return %5 @loc="14:13";
> }
> ()void -> {
> %6 : float = constant @"0.0" @loc="16:20";
> return %6 @loc="16:13";
> };
> return @loc="10:5";
> };
>
> Lowered model:
>
> func @"f" @loc="10:5:..." (%0 : float)float -> {
> %1 : Var<float> = var %0 @"input" @loc="10:5";
> %2 : float = var.load %1 @loc="13:13";
> %3 : float = constant @"0.0" @loc="13:22";
> %4 : boolean = ge %2 %3 @loc="13:13";
> cbranch %4 ^block_1 ^block_2;
>
> ^block_1:
> %5 : float = constant @"1.0" @loc="14:20";
> return %5 @loc="14:13";
>
> ^block_2:
> %6 : float = constant @"0.0" @loc="16:20";
> return %6 @loc="16:13";
>
> ^block_3:
> return @loc="10:5";
> };
>
>
> The compiler produced model is incorrect placing a return operation when it should be an unreachable operation.
>
> There are some reminders in ReflectMethods:
>
> CoreOp.FuncOp scanMethod() {
> scan(body);
> // @@@ Check if unreachable
> appendTerminating(CoreOp::_return);
> CoreOp.FuncOp func = CoreOp.func(name.toString(), stack.body);
> func.setLocation(generateLocation(currentNode, true));
> return func;
> }
>
> 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.)
>
> In this case we can know because there is no return value in scope, but generally we cannot rely upon that.
>
> 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.
>
> 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?
>
> Paul.
More information about the babylon-dev
mailing list