Skip to content

Tolk: Constant folding of negative shift emits PUSHNAN instead of preserving runtime exception #1974

@Gusarich

Description

@Gusarich

The compiler folds 1 << -1 into PUSHNAN at compile time, but the equivalent runtime operation throws range_chk (exit code 5). This changes observable behavior based on whether the shift amount is a constant.

const BAD_SHIFT: int = 1 << -1;

@noinline
fun const_val(): int {
    return BAD_SHIFT;
}

@noinline
fun runtime_val(shift: int): int {
    return 1 << shift;
}

fun onInternalMessage(): (int, int) {
    return (const_val(), runtime_val(-1));
}

Compiles to:

const_val() PROC:<{
  PUSHNAN                 // const path: silently returns NaN
}>

runtime_val() PROC:<{  //  shift
  POW2                    // runtime path: throws for shift=-1
}>

onInternalMessage() PROC:<{
  const_val() CALLDICT
  -1 PUSHINT
  runtime_val() CALLDICT
}>

The runtime path throws exit code 5 (integer out of range) because POW2 range-checks its argument. The constant-folded version bypasses this and silently produces NaN.

Same input, different behavior. The compiler should reject 1 << -1 at compile time rather than folding it to NaN.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions