Skip to content

JIT: Further clean up local definition handling - #135048

Open
jakobbotsch wants to merge 4 commits into
dotnet:mainfrom
jakobbotsch:call-local-def-cleanup
Open

jakobbotsch wants to merge 4 commits into
dotnet:mainfrom
jakobbotsch:call-local-def-cleanup

Conversation

@jakobbotsch

Copy link
Copy Markdown
Member

Move the node visitor to GenTreeCall and inline call definition flag setup into fgMorphCall. Use logical definitions for assertion killing and SSA memory definitions, deduplicating shared physical definitions.

Separate address-exposed local memory definitions from other memory modifications, sharing the SSA bookkeeping for exceptional successors.

Move the node visitor to GenTreeCall and inline call definition flag
setup into fgMorphCall. Use logical definitions for assertion killing
and SSA memory definitions, deduplicating shared physical definitions.

Separate address-exposed local memory definitions from other memory
modifications, sharing the SSA bookkeeping for exceptional successors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e5380c17-dca4-4a54-b4bb-16ad9560f1e9
@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Oct 1, 2026
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

jakobbotsch and others added 2 commits October 1, 2026 22:33
Remove IsEntireLocalDef and redundant definition flag setup in call morph.
Recognize all established local definitions when computing call assignment
effects, and track async resumed indicator definitions in AsyncCallInfo.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e5380c17-dca4-4a54-b4bb-16ad9560f1e9
Avoid the compiler TLS lookup and const_cast in OperRequiresAsgFlag
by checking the return buffer and async resumed indicator flags.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e5380c17-dca4-4a54-b4bb-16ad9560f1e9
@jakobbotsch
jakobbotsch marked this pull request as ready for review October 1, 2026 22:35
Comment thread src/coreclr/jit/morph.cpp
Comment on lines +13117 to +13122
auto visitDef = [=](const auto& def) {
fgKillDependentAssertions(def.GetLclNum() DEBUGARG(tree));
return GenTree::VisitResult::Continue;
};

tree->VisitPhysicalLocalDefNodes(this, visitDef);
tree->VisitLogicalLocalDefs(this, visitDef);

@jakobbotsch jakobbotsch Oct 1, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is the source of the improvements. For example, for

               [000259] UA---------                            └──▌  STORE_LCL_FLD long  (P) V11 tmp6         [+8]
                                                                  ▌    ref    field V11._array (fldOffset=0x0) -> V28 tmp23        
                                                                  ▌    int    field V11._offset (fldOffset=0x8) -> V29 tmp24        
                                                                  ▌    int    field V11._count (fldOffset=0xc) -> V30 tmp25   

previously we would kill V11 which kills assertions about all of V11, V28, V29 and V30. Now using VisitLogicalLocalDefs kills only the assertions about V11, V29 and V30.

(Of course the precision is not the reason for the change, but to make this just work with GT_STORE_LCL_VARS)

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.

@jakobbotsch not sure if it's a correctness issue, but does it mean a store into the padding doesn't kill the "this whole struct is ZeroObj" assertion?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Probably isn't a correctness issue yeah, but regardless, my other change to VisitLogicalLocalDefs will also mean we kill base local for that case.

Once old promotion is removed all of these edge cases will disappear naturally.

Comment on lines +8663 to +8664
return AsCall()->IsOptimizingRetBufAsLocal() ||
(AsCall()->IsAsync() && AsCall()->GetAsyncInfo().DefinesResumedIndicator);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This was a bug introduced with async work. After fixing this earlier phases complained that the async calls weren't marked as GTF_ASG. I fixed that by adding the AsyncCallInfo::DefinedResumedIndicator to model that definition similarly to how we model retbuf definitions (they only become 'actual' definitions starting from local morph now).

Comment thread src/coreclr/jit/morph.cpp
Comment on lines 6494 to 6495

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Unnecessary, GTF_VAR_DEF is set by local morph when the retbuffer/async indicators are recognized as valid definitions that do not need address exposure.

@jakobbotsch

Copy link
Copy Markdown
Member Author

cc @dotnet/jit-contrib PTAL @EgorBo

Another few clean ups before the GT_STORE_LCL_VARS PR.

Diffs. Some minor improvements, I left a comment above where they're from and some other comments for context on the changes.

//
void SsaBuilder::RenamePushMemoryDef(GenTree* defNode, BasicBlock* block)
{
assert(!defNode->OperIsAnyLocal());

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.

My AI reviewer flagged this as reachable:

This can still be reached with a local node. A  STORE_LCL_FLD  into a promoted struct that only touches padding (e.g.  { byte A; long B; } , 1-byte store at  +1 ) yields no logical defs.  anyDefs  stays false, and  RenameDef  (L453–L464) calls this with the store, so the assert fires. The old code handled local nodes here.

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.

using System;
using System.Runtime.CompilerServices;

struct S {
    public byte A;
    public long B;
}

class Program {
    static void Main() => Console.WriteLine(Test(1, 2));

    [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
    static long Test(byte a, long b) {
        S s;
        s.A = a;
        s.B = b;
        Unsafe.Add(ref Unsafe.As<S, byte>(ref s), 1) = 42; // padding-only store
        return Unsafe.As<S, long>(ref s) + s.B;
    }
}

With the PR's JIT it fails with:

Assertion failed '!defNode->OperIsAnyLocal()' in 'Program:Test(byte,long):long'
during 'SSA: insert phis'  File: src\coreclr\jit\ssabuilder.cpp:540

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Hmm, that's rather a bug in VisitLogicalLocalDefs. Let me fix that there.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I pushed a new commit. It has some TP regressions, but once old promotion is removed it can all be simplified a lot.

Report a base-local definition when a dependently promoted store
writes bytes not covered by its fields. Return this requirement from
the range visitor and let callers emit the appropriate definition.

Remove the redundant exact-field fast path and add regression coverage
for padding-only, overlapping, whole-local, and return-buffer writes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e5380c17-dca4-4a54-b4bb-16ad9560f1e9

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants