Cannot deduce type of aggregate phi for small float struct
- Dominant language
- LLVM
- Stars
- 1.7k
- Forks
- 188
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 26
Description
## Summary
Enzyme fails type deduction for an aggregate phi of type `{ <2 x float>, float }`
when differentiating a void function through `__enzyme_autodiff`.
This aggregate shape is produced by optimized C++ for a small three-float struct
returned by value from a runtime dispatch function. The minimized IR below is
smaller than the original C++ pattern, but preserves the same failure mode:
Enzyme reports `Cannot deduce type of phi` while preprocessing the aggregate phi
instead of selecting a usable subelement type or treating inactive/unknown lanes
as non-differentiable.
## Reproducer
Save this as `standalone_reproducer.ll`:
```llvm
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"
define { <2 x float>, float } @runtime_dispatch(i1 %cond) {
entry:
br i1 %cond, label %merge, label %call_branch
call_branch:
%branch_value = call { <2 x float>, float } @branch_model()
br label %merge
merge:
%state = phi { <2 x float>, float } [ %branch_value, %call_branch ], [ zeroinitializer, %entry ]
ret { <2 x float>, float } %state
}
define { <2 x float>, float } @branch_model() {
entry:
ret { <2 x float>, float } { <2 x float> zeroinitializer, float poison }
}
define void @autodiff_entry() {
entry:
call void @__enzyme_autodiff(ptr @kernel_wrapper, i32 0, i32 0, ptr null, ptr null, i32 0, ptr null, ptr null)
ret void
}
define void @kernel_body(ptr %out) {
entry:
%state = call { <2 x float>, float } @runtime_dispatch(i1 false)
%vec = extractvalue { <2 x float>, float } %state, 0
%value = extractelement <2 x float> %vec, i64 0
store float %value, ptr %out, align 4
ret void
}
declare void @__enzyme_autodiff(ptr, i32, i32, ptr, ptr, i32, ptr, ptr)
define void @kernel_wrapper(i32 %begin, i32 %end, ptr %out, i32 %unused, ptr %shadow) {
entry:
call void @kernel_body(ptr %out)
ret void
}
```
Run:
```sh
opt \
-load-pass-plugin=/path/to/LLVMEnzyme-19.so \
-passes=enzyme \
-enzyme-loose-types=1 \
-enzyme-detect-readthrow=0 \
-enzyme-coalese=1 \
-enzyme-noalias=1 \
-enzyme-phi-restructure=1 \
-enzyme-max-cache=1 \
-S standalone_reproducer.ll -o /dev/null
```
## Actual Behavior
With Enzyme commit `f7d66cce57bbd62ba053d65bf985dcadaa324637` and LLVM 19.1.7:
```text
error: :0:0: in function preprocess_runtime_dispatch { <2 x float>, float } (i1): Enzyme: Cannot deduce type of phi %state = phi { <2 x float>, float } [ %branch_value, %call_branch ], [ zeroinitializer, %entry ]{} sz: 16
```
## Expected Behavior
Enzyme should not fail type deduction for the aggregate phi. It should either:
- infer an appropriate scalar float type from the aggregate's subelements, or
- ignore/skip inactive or unknown lanes that are not needed by the derivative.
## Notes
In the original C++ case, `-O3` produced this aggregate phi after inlining/runtime
dispatch of a small struct returned by value. Building the same source with
`-O0` or `-fno-inline` avoided the failure because the aggregate phi was not
formed in the IR passed to Enzyme.
The relevant error path appears to be in `EnzymeLogic.cpp`, where phi handling
queries `TypeTree` for the phi and tries to deduce one scalar float type. If the
aggregate-level type or the first subrange is unknown, the current logic can fail
instead of selecting a usable float subelement or skipping inactive lanes.
Contributor guide
Research direction
Start by saving the supplied IR as standalone_reproducer.ll and running the shown opt command with the Enzyme pass. Inspect aggregate-phi handling in EnzymeLogic.cpp, especially the TypeTree lookup and scalar type deduction. Done means the reproducer no longer reports “Cannot deduce type of phi” and inactive or unknown lanes are handled as described.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100