Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Never use heap for return buffers#112060

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
EgorBo merged 20 commits intodotnet:mainfromEgorBo:non-heap-retbuf
Feb 11, 2025
Merged

Conversation

@EgorBo
Copy link
Member

@EgorBoEgorBo commentedFeb 1, 2025
edited
Loading

CI experiment for#111127

MyStructFoo(stringname,intage){returnnewMyStruct(name,age);}recordstructMyStruct(stringName,intAge);

Was:

; Method Prog:Foo(System.String,int):MyStruct:this (FullOpts)pushrsipushrbxmovrbx,rdxmovrdx,r8movesi,r9dmovrcx,rbxcall     CORINFO_HELP_CHECKED_ASSIGN_REFmov      dword ptr[rbx+0x08],esimovrax,rbxpoprbxpoprsiret; Total bytes of code: 28

Now:

; Method Prog:Foo(System.String,int):MyStruct:this (FullOpts)mov      gword ptr[rdx],r8mov      dword ptr[rdx+0x08],r9dmovrax,rdxret; Total bytes of code: 11

where the write barrier is put at the callsite if needed (presumably, it happens rarely)

Updated stats for write-barriers after#112227 was merged (it is supposed to help reducing the number of bulk barriers):

aspnet-win-x64 SPMI collection:

CORINFO_HELP_ASSIGN_REF:          -0CORINFO_HELP_ASSIGN_BYREF:      -123CORINFO_HELP_CHECKED_ASSIGN_REF: -64CORINFO_HELP_BULK_WRITEBARRIER:  -31

Looks like the aspnet collection has too many missed contexts currently (so the actual numbers are likely 5-10% higher)

MihuBot (PMI for BCL):

CORINFO_HELP_ASSIGN_REF:           -0CORINFO_HELP_ASSIGN_BYREF:       -342CORINFO_HELP_CHECKED_ASSIGN_REF: -838CORINFO_HELP_BULK_WRITEBARRIER:  -300

neon-sunset, NinoFloris, danmoseley, AlgorithmsAreCool, hendriklhf, GerardSmit, MihaZupan, SystematicChaos012, pentp, and PaulusParssinen reacted with rocket emojifilipnavara, En3Tho, BoyBaykiller, PaulusParssinen, and Uladzimir-Lashkevich reacted with eyes emoji
@ghostghost added the area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI labelFeb 1, 2025
@dotnet-policy-service
Copy link
Contributor

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

@EgorBo
Copy link
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@EgorBo
Copy link
MemberAuthor

/azp run runtime-coreclr jitstress, runtime-coreclr gcstress0x3-gcstress0xc, runtime-coreclr gcstress-extra, runtime-coreclr libraries-jitstress, runtime-coreclr libraries-pgo, Fuzzlyn, runtime-coreclr pgostress, runtime-coreclr outerloop

@azure-pipelines
Copy link

Azure Pipelines successfully started running 8 pipeline(s).

STRESS_MODE(POISON_IMPLICIT_BYREFS) \
STRESS_MODE(STORE_BLOCK_UNROLLING) \
STRESS_MODE(THREE_OPT_LAYOUT) \
STRESS_MODE(NONHEAP_RET_BUFFER) \
Copy link
Member

@jkotasjkotasFeb 7, 2025
edited
Loading

Choose a reason for hiding this comment

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

Do we run any of these JIT stress modes with naot? If yes, we may need the helper implemented for naot too.

Also, I am not sure about the durable value of this stress mode and helper. I understand that the helper was useful when implementing the change. Do you think that there is high enough probability that we will passing the heap pointers for return buffers by mistake without noticing it in other ways?

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

Do we run any of these JIT stress modes with naot? If yes, we may need the helper implemented for naot too.

Can't find any evidence that we run jitstress for NAOT even in outerloop and we definitely have no GCStress for it (#107850)

Also, I am not sure about the durable value of this stress mode and helper. I understand that the helper was useful when implementing the change. Do you think that there is high enough probability that we will passing the heap pointers for return buffers by mistake without noticing it in other ways?

I had it locally for R2R too. It seems my test apps fail badly if I remove theimporter code that makes local copies instead of passing heap pointer, even without any explicit stress mode (and the helper), so I presume I can delete it

Copy link
Member

@jkotasjkotas left a comment

Choose a reason for hiding this comment

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

Thanks!

EgorBo reacted with thumbs up emojiEn3Tho reacted with hooray emoji
@EgorBo
Copy link
MemberAuthor

EgorBo commentedFeb 8, 2025
edited
Loading

@jakobbotsch @dotnet/jit-contrib does the jit side look good (beside leaving a few things to follow up PRs as improvements on top of it)

Comment on lines 12687 to 12690
if (op->OperIsScalarLocal() && (op->AsLclVarCommon()->GetLclNum() == impInlineRoot()->info.compRetBuffArg))
{
return true;
}
Copy link
Member

Choose a reason for hiding this comment

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

I don't think it's ok for this to return true without assigninglclVarTreeOut.
I think it would be better to add a new function that checks for the property we want, e.g.PointsOutsideHeap or similar.GenTreeIndir::IsAddressNotOnHeap could probably be switched to use it as well.

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

@jakobbotsch ah good idea, addressed

Comment on lines 959 to 969
if (op->OperIs(GT_ADD))
{
// If we have (base + offset), inspect the base. We assume someone else normalized the tree
// so the constant offset is always on the right.
GenTree* op2 = op->gtGetOp2();
if (op2->TypeIs(TYP_I_IMPL) && op2->IsCnsIntOrI() && !op2->IsIconHandle() &&
!fgIsBigOffset(op2->AsIntCon()->IconValue()))
{
returnfgAddrCouldBeHeap(op->gtGetOp1());
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Could usegtPeelOffsets here.

Copy link
Member

Choose a reason for hiding this comment

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

Probably best to do it up before the check forop->OperIs(GT_LCL_ADDR), it might also get some cases on the retbuffer

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

I've already checked that it doesn't find anything new, but I guess wouldn't hurt

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

addressed

Comment on lines 854 to 859
GenTree* spilledCall = gtNewStoreLclVarNode(tmp, srcCall);
GenTree* comma = gtNewOperNode(GT_COMMA, store->TypeGet(), spilledCall,
gtNewLclvNode(tmp, lvaGetDesc(tmp)->TypeGet()));
store->Data() = comma;
comma->AsOp()->gtOp1 = impStoreStruct(spilledCall, curLevel, pAfterStmt, di, block);
return impStoreStruct(store, curLevel, pAfterStmt, di, block);
Copy link
Member

Choose a reason for hiding this comment

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

We still have the problem here that this reorders the LHS of the store with the RHS. I think if the LHS has side effects/ordering effects we need to introduce a local and another comma for it to evaluate it before the call.

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

@jakobbotsch can you elaborate? we spill the destination to a local (even before my change)

Copy link
Member

Choose a reason for hiding this comment

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

Where is the destination spilled to a local? I think if you callimpStoreStruct with a store likeSTORE_BLK(Foo(), Bar()), then the code here will reorderFoo() so that it happens afterBar().

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

@jakobbotsch I think I've addressed it in4a48e64 Presumably, GT_RET_EXPR doesn't need special treatment, as we don't spill call their by hands

Copy link
Member

Choose a reason for hiding this comment

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

For inlining we already reorder things because of#112053, so regardless it's probably fine. Once that is fixed we can look into if anything is necessary here to keep the LHS before the call as well.

((store->AsIndir()->Addr()->gtFlags & GTF_ALL_EFFECT) != 0))
{
unsigned lclNum = lvaGrabTemp(true DEBUGARG("fgMakeTemp is creating a new local variable"));
impStoreToTemp(lclNum, store->AsIndir()->Addr(), curLevel, pAfterStmt, di, block);
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we can useimpStoreStruct here since this function is called from outside import viagtNewTempStore. I think it needs to create a comma, or only call this function in some cases (see the checks below forGT_COMMA)

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

um.. whatimpStoreStruct are your referring here? did you mean impStoreToTemp? Also, seems like this function already appends stuff to statements so it's weird expect it to not?

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

I guess it's just an implicit contract that when gtNewTempStore calls it - it does not?

Copy link
Member

Choose a reason for hiding this comment

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

Yes I meantimpStoreTemp

seems like this function already appends stuff to statements so it's weird expect it to not?

Where does it do that? I think we only do that for theGT_COMMA case, and it has guards to ensure that only happens during import

Copy link
Member

Choose a reason for hiding this comment

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

We spoke offline and Egor convinced me that actually no reordering is happening here, so we don't need to do any spilling here. Sorry about that.

EgorBo reacted with thumbs up emoji
Copy link
Member

@jakobbotschjakobbotsch left a comment

Choose a reason for hiding this comment

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

LGTM

@EgorBoEgorBo merged commitb1ab309 intodotnet:mainFeb 11, 2025
110 of 112 checks passed
@EgorBoEgorBo deleted the non-heap-retbuf branchFebruary 11, 2025 23:32
@github-actionsgithub-actionsbot locked and limited conversation to collaboratorsMar 14, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account?Sign in.

Reviewers

@jkotasjkotasjkotas approved these changes

@jakobbotschjakobbotschjakobbotsch approved these changes

@MichalStrehovskyMichalStrehovskyAwaiting requested review from MichalStrehovskyMichalStrehovsky is a code owner

Assignees

@EgorBoEgorBo

Labels

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

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

4 participants

@EgorBo@jakobbotsch@jkotas@NinoFloris

[8]ページ先頭

©2009-2025 Movatter.jp