Skip to content

Unary minus on function arguments / let bindings folds incorrectly #1

@PearCoding

Description

@PearCoding

Summary

Unary minus (`-`) applied to a function parameter or let-bound variable is miscompiled. In HikariRenderer's PExpr stdlib, `abs(-3.5)` returns `-3.5` instead of `3.5`.

Reproduction

Using the PExpr compiler embedded in HikariRenderer (`SVMCompiler`, `dev` branch of PExpr), with all optimisation passes enabled:

Expression Expected Actual
`abs(-3.5)` `3.5` `-3.5`
`abs(3.5)` `3.5` `3.5` ✓
`abs(-1.0)` `1.0` `-1.0`
`if (-3.5 < 0.0) { -(-3.5) } else { -3.5 }` `3.5` `3.5` ✓
`-(-3.5)` `3.5` `3.5` ✓
`let a = -3.5 in -a` `3.5` `0`
`let a = -3.5 in 0.0 - a` `3.5` `0`

The stdlib `abs` is defined as:
```
fn abs(a:num) = if a < 0 { -a } else { a };
```

The SSA dump for `abs(-3.5)` is a single line:
```
return -3.5:num
```
The `abs` call is fully folded away and the unary minus on the function parameter `-a` has been dropped.

Scope

  • An explicit `if` with literal branches works — branch selection is fine.
  • A top-level `-(-literal)` works — unary minus on a literal is fine.
  • The bug shows up specifically when unary minus is applied to a function argument or a let-bound variable, i.e. when the operand is a reference to a binding being substituted/inlined.

Likely cause

Constant folding/inlining substitutes the argument's value into the function body but loses (or mis-handles) the surrounding unary minus. The `0 - a` path folding to `0` in the let case suggests `a` is being resolved to `0` when read from the binding — possibly an undefined/zero-initialised register slot for the let binding in one of the lowering passes.

Workaround

Use arithmetic negation instead of unary minus: `0.0 - x`. This also fails for let-bound variables (returns 0), so the workaround only applies to inlined literals.

Environment

  • PExpr: `dev` branch as fetched by PearCoding/HikariRenderer (CPMAddPackage)
  • Host compiler: MSVC 19.44, C++20
  • OS: Windows 11 x64

Filed while building out CI-runnable unit tests for HikariRenderer's shader system.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions