Skip to content

autodiff: Normalize typetree struct field types - #160701

Open
Dnreikronos wants to merge 3 commits into
rust-lang:mainfrom
Dnreikronos:autodiff/typetree_normalize_array_const
Open

autodiff: Normalize typetree struct field types#160701
Dnreikronos wants to merge 3 commits into
rust-lang:mainfrom
Dnreikronos:autodiff/typetree_normalize_array_const

Conversation

@Dnreikronos

@Dnreikronos Dnreikronos commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Fixes #160635

-Zautodiff=Enable was ICEing on structs with fields like *mut [f32; N]. FieldDef::ty returns Unnormalized, and we were just calling skip_norm_wip, so recursion hit struct_tail_for_codegen with an unevaluated anon const length. Same root cause also quietly emptied TypeTrees for plain [T; N] fields, fyi.

Now we normalize with TypingEnv::fully_monomorphized before walking struct fields. Imo that's the right call here: we're already post-mono in codegen, and it lines up with the Unnormalized WIP migration instead of spreading more skip_norm_wip around. Btw I added a run-make regression covering both faces of the bug.

Idk if Enzyme will still choke on murkier shadow-pointer cases irl, but at least rustc stops panicking. Ltm if the FileCheck strings look too layout-locked for other targets and I can loosen them asap.

FieldDef::ty returns Unnormalized, so skipping normalization left
anon-const array lengths unevaluated. That ICEd in
struct_tail_for_codegen and emptied TypeTrees for plain [T; N] fields.
Normalize with TypingEnv::fully_monomorphized before recursing.
Cover both the ICE path through *mut [T; N] struct fields and the
silent empty-TypeTree case for plain [T; N] fields.
@rustbot rustbot added A-run-make Area: port run-make Makefiles to rmake.rs S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Aug 7, 2026
@rustbot

rustbot commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

r? @davidtwco

rustbot has assigned @davidtwco.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 75 candidates
  • Random selection from 20 candidates

@ZuseZ4

ZuseZ4 commented Aug 10, 2026

Copy link
Copy Markdown
Member

r? me

@rustbot rustbot assigned ZuseZ4 and unassigned davidtwco Aug 10, 2026
INLINE-NOT: define
INLINE: call void @llvm.memcpy{{.*}}"enzyme_type"="{[0]:Pointer, [0,0]:Float@float, [0,32]:Float@float}"

; Enzyme accepts the ICE-shaped PtrArray TypeTree (not just rustc emission).

@ZuseZ4 ZuseZ4 Aug 11, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does ICE-shaped mean? Same for " (not just rustc emission)"

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah fair, "ICE-shaped" was me being cute and it just confused things lol. dropped that whole comment. imo if the FileCheck already proves the TypeTree shape we don't need a little essay next to it. ltm if the new wording still feels off.

*b = *a;
}

// Run Enzyme over the ICE-shaped type so metadata is not only emitted but accepted.

@ZuseZ4 ZuseZ4 Aug 11, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment doesn't give relevant info (All metadata we emit should be accepted)

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree, that comment was kinda pointless. if we emit it, Enzyme should take it; no reason to special-case that in the test notes. deleted it.


// Regression test for #160635: non-literal array lengths (anon consts) in struct
// fields must be normalized before typetree recursion. Without that, `*mut [f32; N]`
// ICEs in `struct_tail_for_codegen`, and a plain `[f32; N]` field silently yields

@ZuseZ4 ZuseZ4 Aug 11, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah this. Can you please update the comments to something that briefly explains what a struct_tail_for_codegen is? (E.g. along the first two sentences from the fn def).

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated. fyi I basically stole the "deepest trailing field / unsizing tail" bit from the fn docs, since that's the part that actually bites us here when the anon const isn't normalized yet. hope that reads clearer.

PTR-NOT: define
PTR: call void @llvm.memcpy{{.*}}"enzyme_type"="{[0]:Pointer, [0,0]:Pointer, [0,0,-1]:Float@float, [0,8]:Float@float, [0,12]:Float@float}"

; Silent case: plain [T; N] field produces float metadata (not an empty subtree).

@ZuseZ4 ZuseZ4 Aug 11, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Silent case: ", "Known limitation" etc read very llm-y. can you shorten the comments a bit so it reads more natural? I curently find them a bit confusing.

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah those comments were doing too much. shortened them a bunch. btw I kept one short note that we still only classify the first inline element rn, mainly so nobody thinks the test is claiming full array coverage. ltm if even that feels like too much.


#[derive(Copy, Clone)]
#[repr(C)]
pub struct InlineArray {

@ZuseZ4 ZuseZ4 Aug 11, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wsmoses what typetree do you expect to be generated here, especially for larger N, of say 2048? Currently we only generate it for offset 0 of data and for scale.
Generating 2048 offsets seems extremely wasteful and -1 would be wrong, in the general case were scale and data have different base types (e.g. scale were int).
Afaik Enzyme doesn't directly let frontend generate typetree ranges?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same place I'm stuck tbh. dense offsets for N=2048 feel pretty wasteful, and -1 is wrong once scale isn't float. afaik Enzyme still doesn't give frontends a clean range form, so I'm not trying to "solve" that in this PR.

imo we keep the normalize fix + the i32 scale regression here, and wait for @wsmoses on what rustc should emit for big inline arrays. ltm what you'd want that follow-up to look like.

#[repr(C)]
pub struct InlineArray {
pub data: [f32; N],
pub scale: f32,

@ZuseZ4 ZuseZ4 Aug 11, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would the test still work if scale were another type? That makes it a bit more clear why we can't just simplify it to -1 (float everywhere)

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good call. flipped scale to i32 and the FileCheck now wants Integer at byte 32. imo that makes the "can't just slap [-1]:Float on the whole struct" point way more obvious irl.

; Silent case: plain [T; N] field produces float metadata (not an empty subtree).
; Known limitation: the struct arm collapses array element offset -1 to the field
; byte offset, so only byte 0 of `data: [f32; 8]` is classified as Float; bytes
; 4..32 stay unclassified (unlike pointer-to-array, which preserves [-1]).

@ZuseZ4 ZuseZ4 Aug 11, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds like a bad footgun, let's see what the enzyme author suggests.

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah it's a real footgun. for this PR I left the current first-element behavior alone and just made the test honest about it. idk what the right compact encoding is yet, so I'd rather wait for William than invent something weird on our side. can chase the full-array case in a follow-up asap once that's clearer.

@ZuseZ4

ZuseZ4 commented Aug 11, 2026

Copy link
Copy Markdown
Member

Thanks! Seems like quite an easy fix, mostly left document nits. But let's also see if we can fix the weird case of not generating typetrees for all following array elements, that feels like it would otherwise cause headaches down the road. Not really sure what we want to generate though, so let's ask the author.

Drop the unhelpful acceptance wording, briefly explain the
struct_tail_for_codegen ICE path, and make scale an i32 so the
inline-array case cannot be hand-waved as floats everywhere.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-run-make Area: port run-make Makefiles to rmake.rs S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ICE]: autodiff fails compiling gemm-f32 microkernel

4 participants