Enzyme generates undef-fed tape PHIs for packed-state nested guard reproducer
- Dominant language
- LLVM
- Stars
- 1.7k
- Forks
- 188
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 22
Description
https://tinyurl.com/2c2v5q9u
## Summary
On current Enzyme `main` (`d0749cbb`, `Attempt to fix rematerialization ficticious phi issues (#2827)`), the attached LLVM IR reproducer still generates `undef`-fed tape state in `augmented_eval`.
This looks related to the old nested-guard family from #2629, but not like the exact same control-flow bug. In this reproducer, reverse still remains gated by the saved outer state, but Enzyme still packs `undef` into saved `i1`, `ptr`, and `double` values along inactive paths.
So this appears to be a remaining tape / PHI / rematerialization issue rather than a duplicate of the specific nested-predicate control-flow bug fixed for #2629.
## Attached reproducer
The reproducer is the attached LLVM IR file:
- `packed_state_outer_guard_undef_tape.ll`
It is self-contained and does not depend on any C++ source or Cromwell code.
The reduced shape is:
- packed state with booleans and an optional pointer
- outer guard around a helper call
- nested helper branches inside that helper
- a looped dot-product path that Enzyme tapes as `{ ptr, double }`
- a later unrelated optional-pointer join
## Reproduction
The file already contains `RUN:` lines for the Enzyme test suite.
Equivalent local reproduction command:
```bash
opt < packed_state_outer_guard_undef_tape.ll \
-load-pass-plugin=/path/to/LLVMEnzyme.so \
-passes="enzyme,function(sroa,mem2reg,early-cse,simplifycfg,instsimplify,correlated-propagation,simplifycfg,adce)" \
-S -enzyme-preopt=0 -enzyme-detect-readthrow=0 | \
FileCheck packed_state_outer_guard_undef_tape.ll
```
## Problematic transformed shape
In the transformed IR, Enzyme emits:
```llvm
define internal { { ptr, ptr, { double, double, double }, ptr, i1, i1, i1, double, double, ptr, i1, double }, double } @augmented_eval(...)
```
and the scalarized output still contains `undef`-fed tape fields such as:
```llvm
%.sroa.14.0 = phi i1 [ %has_rotation, %with.frame ], [ undef, %entry ]
%.sroa.16.0 = phi i1 [ %has_translation, %with.frame ], [ undef, %entry ]
%.sroa.10.0 = phi ptr [ %subcache, %with.dot ], [ undef, %after.frame ]
%.sroa.26.0 = phi double [ undef, %have.second ], [ %roughness_limit, %no.second ]
```
Those values are then packed back into the tape via `insertvalue`.
The attached `.ll` file checks exactly for this shape.
## Why this does not look like a straight duplicate of #2629
- #2629 was about incorrect reverse CFG reconstruction for nested inactive-outer / active-inner predicates.
- The fix there delayed inner predicate materialization and zero-initialized predicate caches.
- In this reproducer, reverse is still gated by the saved outer state.
- The remaining issue is that the tape payload itself still carries `undef` through saved fields.
## Expected behavior
Enzyme should not emit `undef` into saved reverse/tape state for semantically "not executed" paths. Those values should have a safe inactive default, or the reverse should be structured so such tape fields are not materialized at all.
## Actual behavior
Current `main` still emits `undef`-fed saved `i1`, `ptr`, and `double` values in the tape for this attached IR reproducer.
## Question
Is this expected / benign IR, or is this still a real remaining bug in Enzyme's tape construction / PHI rematerialization for packed-state nested-guard code?
Contributor guide
Assessment
This issue has not been assessed yet.