EnzymeAD / EnzymeAD/Enzyme

Enzyme generates undef-fed tape PHIs for packed-state nested guard reproducer

Open
#2,834 1 comment 0 reactions 0 assignees View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.