Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 5.6k
Intrinsify Unsafe.Read/Write/Copy, handle struct BitCast#85562
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Uh oh!
There was an error while loading. Please reload this page.
Merged
Changes from all commits
Commits
Show all changes
64 commits
Select commit
Hold shift + click to select a range
1e54aa0
Intrinsify Unsafe.Read/Write, handle struct BitCast
MichalPetryka 5e78c9c
Fix broken rebase
MichalPetryka 93399c2
Handle small type extension
MichalPetryka 8987b69
Fix formatting
MichalPetryka 858f39c
Fix swapped operands
MichalPetryka a193350
Use right helper
MichalPetryka db54e97
Don't loose indir flags
MichalPetryka 9c2ee9e
Fix build
MichalPetryka 3e5003f
Fix missed deref
MichalPetryka b3e7e97
Also mask indir flags
MichalPetryka 66f111b
Rename variables, fix structs
MichalPetryka a5bb60b
Fix build
MichalPetryka 0922ea6
Merge upstream
MichalPetryka 36ab91d
Update importer.cpp
MichalPetryka 84a3edc
Resolve conflicts
MichalPetryka b911984
Fix 32bit bug, simplify code
MichalPetryka 2982fd4
Fix merge
MichalPetryka feb0acc
Simplify code
MichalPetryka 08e9ece
Update importercalls.cpp
MichalPetryka 9204f80
Update importer.cpp
MichalPetryka 36eecf9
Remove redundant nullchecks
MichalPetryka 3ed32ad
Format code
MichalPetryka 6cbaa45
Mark the local as having new uses
MichalPetryka 6c758ee
Update targetosarch.h
MichalPetryka 13ece70
Reword comments
MichalPetryka d68aed9
Update targetosarch.h
MichalPetryka 873a914
Handle small types
MichalPetryka c9b274c
Reformat code
MichalPetryka 290bf27
Commit missed changes
MichalPetryka 3d77bb0
Fix check
MichalPetryka 15aa641
Merge branch 'main' into bitcast-indir
MichalPetryka 4ab78a0
Format code
MichalPetryka e1911ee
Add tests for small types and misalignment
MichalPetryka 38f10fc
Fix a typo, add more tests
MichalPetryka b69aaa7
Adjust small type handling
MichalPetryka 46c45cc
Fix typo
MichalPetryka 0c245fb
Fix warning
MichalPetryka 6ca55ac
Format code
MichalPetryka 1d4191d
Merge branch 'main' into bitcast-indir
MichalPetryka 455b468
Merge branch 'main' into bitcast-indir
MichalPetryka 7544cff
Merge upstream
MichalPetryka 3aed08b
Fix merge
MichalPetryka f68aec0
Fix merge
MichalPetryka 23e48d2
Rename variables
MichalPetryka 964ab38
Fix typo
MichalPetryka 7253d9e
Format code
MichalPetryka 81fd3c7
Merge upstream
MichalPetryka e653348
Add missing free
MichalPetryka 86ff6d4
Merge upstream
MichalPetryka 5111f6e
Add IL tests
MichalPetryka 8174abd
Update BitCast.il
MichalPetryka b9160be
Fix IL test
MichalPetryka d864688
Intrinsify Copy too
MichalPetryka 588d55e
Update UnsafeTests.cs
MichalPetryka 674d605
Update UnsafeTests.cs
MichalPetryka 43ebe78
Update UnsafeTests.cs
MichalPetryka 8e52b2f
Update src/tests/JIT/Intrinsics/BitCast.il
MichalPetryka 300951c
Add struct copy tests
MichalPetryka 7b9afe4
Merge branch 'dotnet:main' into bitcast-indir
MichalPetryka ac25690
Merge branch 'dotnet:main' into bitcast-indir
MichalPetryka add3666
Merge branch 'dotnet:main' into bitcast-indir
MichalPetryka 5754b95
Merge branch 'dotnet:main' into bitcast-indir
MichalPetryka 88e8829
Merge branch 'dotnet:main' into bitcast-indir
MichalPetryka 87950df
Merge branch 'dotnet:main' into bitcast-indir
MichalPetryka File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -807,8 +807,10 @@ GenTree* Compiler::impStoreStruct(GenTree* store, | ||
| WellKnownArg wellKnownArgType = | ||
| srcCall->ShouldHaveRetBufArg() ? WellKnownArg::RetBuffer : WellKnownArg::None; | ||
| GenTree* destAddr = impGetStructAddr(store, CHECK_SPILL_ALL, /* willDeref */ true); | ||
| NewCallArg newArg = NewCallArg::Primitive(destAddr).WellKnown(wellKnownArgType); | ||
| // TODO-Bug?: verify if flags matter here | ||
EgorBo marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| GenTreeFlags indirFlags = GTF_EMPTY; | ||
| GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, &indirFlags); | ||
| NewCallArg newArg = NewCallArg::Primitive(destAddr).WellKnown(wellKnownArgType); | ||
| #if !defined(TARGET_ARM) | ||
| // Unmanaged instance methods on Windows or Unix X86 need the retbuf arg after the first (this) parameter | ||
| @@ -909,7 +911,9 @@ GenTree* Compiler::impStoreStruct(GenTree* store, | ||
| if (call->ShouldHaveRetBufArg()) | ||
| { | ||
| // insert the return value buffer into the argument list as first byref parameter after 'this' | ||
| GenTree* destAddr = impGetStructAddr(store, CHECK_SPILL_ALL, /* willDeref */ true); | ||
| // TODO-Bug?: verify if flags matter here | ||
| GenTreeFlags indirFlags = GTF_EMPTY; | ||
| GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, &indirFlags); | ||
| call->gtArgs.InsertAfterThisOrFirst(this, | ||
| NewCallArg::Primitive(destAddr).WellKnown(WellKnownArg::RetBuffer)); | ||
| @@ -926,16 +930,17 @@ GenTree* Compiler::impStoreStruct(GenTree* store, | ||
| { | ||
| // Since we are assigning the result of a GT_MKREFANY, "destAddr" must point to a refany. | ||
| // TODO-CQ: we can do this without address-exposing the local on the LHS. | ||
| GenTree* destAddr = impGetStructAddr(store, CHECK_SPILL_ALL, /* willDeref */ true); | ||
| GenTree* destAddrClone; | ||
| GenTreeFlags indirFlags = GTF_EMPTY; | ||
| GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, &indirFlags); | ||
| GenTree* destAddrClone; | ||
| destAddr = impCloneExpr(destAddr, &destAddrClone, curLevel, pAfterStmt DEBUGARG("MKREFANY assignment")); | ||
| assert(OFFSETOF__CORINFO_TypedReference__dataPtr == 0); | ||
| assert(destAddr->gtType == TYP_I_IMPL || destAddr->gtType == TYP_BYREF); | ||
| // Append the store of the pointer value. | ||
| // TODO-Bug: the pointer value can be a byref. Use its actual type here instead of TYP_I_IMPL. | ||
| GenTree* ptrFieldStore = gtNewStoreIndNode(TYP_I_IMPL, destAddr, src->AsOp()->gtOp1); | ||
| GenTree* ptrFieldStore = gtNewStoreIndNode(TYP_I_IMPL, destAddr, src->AsOp()->gtOp1, indirFlags); | ||
| if (pAfterStmt) | ||
| { | ||
| Statement* newStmt = gtNewStmt(ptrFieldStore, usedDI); | ||
| @@ -1020,51 +1025,59 @@ GenTree* Compiler::impStoreStructPtr(GenTree* destAddr, GenTree* value, unsigned | ||
| } | ||
| //------------------------------------------------------------------------ | ||
| // impGetStructAddr: Get the address of a struct value / location. | ||
| // impGetNodeAddr: Get the address of a value. | ||
| // | ||
| // Arguments: | ||
| // structVal - The value in question | ||
| // curLevel - Stack level for spilling | ||
| // willDeref - Whether the caller will dereference the address | ||
| // val - The value in question | ||
| // curLevel - Stack level for spilling | ||
| // pDerefFlags - Flags to be used on dereference, nullptr when | ||
| // the address won't be dereferenced. Returned flags | ||
| // are included in the GTF_IND_COPYABLE_FLAGS mask. | ||
| // | ||
| // Return Value: | ||
| // In case "structVal" can represent locations (is an indirection/local), | ||
| // In case "val" represents a location (is an indirection/local), | ||
| // will return its address. Otherwise, address of a temporary assigned | ||
| // the value of "structVal" will be returned. | ||
| // the value of "val" will be returned. | ||
| // | ||
| GenTree* Compiler::impGetStructAddr(GenTree* structVal, unsigned curLevel, bool willDeref) | ||
| GenTree* Compiler::impGetNodeAddr(GenTree* val, unsigned curLevel, GenTreeFlags* pDerefFlags) | ||
| { | ||
| assert(varTypeIsStruct(structVal)); | ||
| switch (structVal->OperGet()) | ||
| if (pDerefFlags != nullptr) | ||
| { | ||
| *pDerefFlags = GTF_EMPTY; | ||
| } | ||
| switch (val->OperGet()) | ||
| { | ||
| case GT_BLK: | ||
| case GT_IND: | ||
| case GT_STOREIND: | ||
| case GT_STORE_BLK: | ||
| if (willDeref) | ||
| if (pDerefFlags != nullptr) | ||
| { | ||
| return structVal->AsIndir()->Addr(); | ||
| *pDerefFlags = val->gtFlags & GTF_IND_COPYABLE_FLAGS; | ||
| return val->AsIndir()->Addr(); | ||
| } | ||
| break; | ||
| case GT_LCL_VAR: | ||
| case GT_STORE_LCL_VAR: | ||
| return gtNewLclVarAddrNode(structVal->AsLclVar()->GetLclNum(), TYP_BYREF); | ||
| val->gtFlags |= GTF_VAR_MOREUSES; | ||
| return gtNewLclVarAddrNode(val->AsLclVar()->GetLclNum(), TYP_BYREF); | ||
| case GT_LCL_FLD: | ||
| case GT_STORE_LCL_FLD: | ||
| return gtNewLclAddrNode(structVal->AsLclFld()->GetLclNum(), structVal->AsLclFld()->GetLclOffs(), TYP_BYREF); | ||
| val->gtFlags |= GTF_VAR_MOREUSES; | ||
| return gtNewLclAddrNode(val->AsLclFld()->GetLclNum(), val->AsLclFld()->GetLclOffs(), TYP_BYREF); | ||
| case GT_COMMA: | ||
| impAppendTree(structVal->AsOp()->gtGetOp1(), curLevel, impCurStmtDI); | ||
| return impGetStructAddr(structVal->AsOp()->gtGetOp2(), curLevel, willDeref); | ||
| impAppendTree(val->AsOp()->gtGetOp1(), curLevel, impCurStmtDI); | ||
| return impGetNodeAddr(val->AsOp()->gtGetOp2(), curLevel, pDerefFlags); | ||
| default: | ||
| break; | ||
| } | ||
| unsigned lclNum = lvaGrabTemp(true DEBUGARG("location for address-of(RValue)")); | ||
| impStoreTemp(lclNum, structVal, curLevel); | ||
| impStoreTemp(lclNum, val, curLevel); | ||
| // The 'return value' is now address of the temp itself. | ||
| return gtNewLclVarAddrNode(lclNum, TYP_BYREF); | ||
| @@ -3000,7 +3013,9 @@ int Compiler::impBoxPatternMatch(CORINFO_RESOLVED_TOKEN* pResolvedToken, | ||
| GenTree* objToBox = impPopStack().val; | ||
| // Spill struct to get its address (to access hasValue field) | ||
| objToBox = impGetStructAddr(objToBox, CHECK_SPILL_ALL, true); | ||
| // TODO-Bug?: verify if flags matter here | ||
| GenTreeFlags indirFlags = GTF_EMPTY; | ||
| objToBox = impGetNodeAddr(objToBox, CHECK_SPILL_ALL, &indirFlags); | ||
| static_assert_no_msg(OFFSETOF__CORINFO_NullableOfT__hasValue == 0); | ||
| impPushOnStack(gtNewIndir(TYP_BOOL, objToBox), typeInfo(TYP_INT)); | ||
| @@ -3348,7 +3363,9 @@ void Compiler::impImportAndPushBox(CORINFO_RESOLVED_TOKEN* pResolvedToken) | ||
| return; | ||
| } | ||
| op1 = gtNewHelperCallNode(boxHelper, TYP_REF, op2, impGetStructAddr(exprToBox, CHECK_SPILL_ALL, true)); | ||
| // TODO-Bug?: verify if flags matter here | ||
| GenTreeFlags indirFlags = GTF_EMPTY; | ||
| op1 = gtNewHelperCallNode(boxHelper, TYP_REF, op2, impGetNodeAddr(exprToBox, CHECK_SPILL_ALL, &indirFlags)); | ||
| } | ||
| /* Push the result back on the stack, */ | ||
| @@ -7968,7 +7985,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) | ||
| } | ||
| else | ||
| { | ||
| op1 = impGetStructAddr(op1, CHECK_SPILL_ALL, false); | ||
| op1 = impGetNodeAddr(op1, CHECK_SPILL_ALL, nullptr); | ||
| } | ||
| JITDUMP("\n ... optimized to ...\n"); | ||
| @@ -8908,7 +8925,9 @@ void Compiler::impImportBlockCode(BasicBlock* block) | ||
| BADCODE3("Unexpected opcode (has to be LDFLD)", ": %02X", (int)opcode); | ||
| } | ||
| obj = impGetStructAddr(obj, CHECK_SPILL_ALL, true); | ||
| // TODO-Bug?: verify if flags matter here | ||
| GenTreeFlags indirFlags = GTF_EMPTY; | ||
| obj = impGetNodeAddr(obj, CHECK_SPILL_ALL, &indirFlags); | ||
| } | ||
| op1 = gtNewFieldAddrNode(resolvedToken.hField, obj, fieldInfo.offset); | ||
| @@ -9661,12 +9680,13 @@ void Compiler::impImportBlockCode(BasicBlock* block) | ||
| else | ||
| { | ||
| // Get the address of the refany | ||
| op1 = impGetStructAddr(op1, CHECK_SPILL_ALL, /* willDeref */ true); | ||
| GenTreeFlags indirFlags = GTF_EMPTY; | ||
| op1 = impGetNodeAddr(op1, CHECK_SPILL_ALL, &indirFlags); | ||
| // Fetch the type from the correct slot | ||
| op1 = gtNewOperNode(GT_ADD, TYP_BYREF, op1, | ||
| gtNewIconNode(OFFSETOF__CORINFO_TypedReference__type, TYP_I_IMPL)); | ||
| op1 = gtNewIndir(TYP_BYREF, op1); | ||
| op1 = gtNewIndir(TYP_BYREF, op1, indirFlags); | ||
| } | ||
| // Convert native TypeHandle to RuntimeTypeHandle. | ||
Oops, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.