Skip to content

Commit 8d2535d

Browse files
Intrinsify Unsafe.Read/Write/Copy, handle struct BitCast (#85562)
Co-authored-by: Egor Bogatov <[email protected]>
1 parent 66556c4 commit 8d2535d

File tree

12 files changed

+548
-140
lines changed

12 files changed

+548
-140
lines changed

src/coreclr/inc/targetosarch.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ class TargetOS
4242
class TargetArchitecture
4343
{
4444
public:
45+
#ifdef TARGET_64BIT
46+
static const bool Is64Bit = true;
47+
#else
48+
static const bool Is64Bit = false;
49+
#endif
4550
#ifdef TARGET_ARM
4651
static const bool IsX86 = false;
4752
static const bool IsX64 = false;

src/coreclr/jit/compiler.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9647,9 +9647,9 @@ void cTreeFlags(Compiler* comp, GenTree* tree)
96479647
{
96489648
chars += printf("[VAR_ITERATOR]");
96499649
}
9650-
if (tree->gtFlags & GTF_VAR_CLONED)
9650+
if (tree->gtFlags & GTF_VAR_MOREUSES)
96519651
{
9652-
chars += printf("[VAR_CLONED]");
9652+
chars += printf("[VAR_MOREUSES]");
96539653
}
96549654
if (!comp->lvaGetDesc(tree->AsLclVarCommon())->lvPromoted)
96559655
{

src/coreclr/jit/compiler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4087,7 +4087,7 @@ class Compiler
40874087
BasicBlock* block = nullptr);
40884088
GenTree* impStoreStructPtr(GenTree* destAddr, GenTree* value, unsigned curLevel);
40894089

4090-
GenTree* impGetStructAddr(GenTree* structVal, unsigned curLevel, bool willDeref);
4090+
GenTree* impGetNodeAddr(GenTree* val, unsigned curLevel, GenTreeFlags* pDerefFlags);
40914091

40924092
var_types impNormStructType(CORINFO_CLASS_HANDLE structHnd, CorInfoType* simdBaseJitType = nullptr);
40934093

src/coreclr/jit/fginline.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1632,7 +1632,7 @@ Statement* Compiler::fgInlinePrependStatements(InlineInfo* inlineInfo)
16321632

16331633
GenTree* argSingleUseNode = argInfo.argBashTmpNode;
16341634

1635-
if ((argSingleUseNode != nullptr) && !(argSingleUseNode->gtFlags & GTF_VAR_CLONED) && argIsSingleDef)
1635+
if ((argSingleUseNode != nullptr) && !(argSingleUseNode->gtFlags & GTF_VAR_MOREUSES) && argIsSingleDef)
16361636
{
16371637
// Change the temp in-place to the actual argument.
16381638
// We currently do not support this for struct arguments, so it must not be a GT_BLK.

src/coreclr/jit/gentree.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8781,7 +8781,7 @@ GenTree* Compiler::gtClone(GenTree* tree, bool complexOK)
87818781

87828782
FINISH_CLONING_LCL_NODE:
87838783
// Remember that the local node has been cloned. Below the flag will be set on 'copy' too.
8784-
tree->gtFlags |= GTF_VAR_CLONED;
8784+
tree->gtFlags |= GTF_VAR_MOREUSES;
87858785
copy->AsLclVarCommon()->SetSsaNum(tree->AsLclVarCommon()->GetSsaNum());
87868786
assert(!copy->AsLclVarCommon()->HasSsaName() || ((copy->gtFlags & GTF_VAR_DEF) == 0));
87878787
break;
@@ -8952,7 +8952,7 @@ GenTree* Compiler::gtCloneExpr(
89528952
else
89538953
{
89548954
// Remember that the local node has been cloned. The flag will be set on 'copy' as well.
8955-
tree->gtFlags |= GTF_VAR_CLONED;
8955+
tree->gtFlags |= GTF_VAR_MOREUSES;
89568956
copy = gtNewLclvNode(tree->AsLclVar()->GetLclNum(),
89578957
tree->gtType DEBUGARG(tree->AsLclVar()->gtLclILoffs));
89588958
copy->AsLclVarCommon()->SetSsaNum(tree->AsLclVarCommon()->GetSsaNum());
@@ -8967,7 +8967,7 @@ GenTree* Compiler::gtCloneExpr(
89678967
else
89688968
{
89698969
// Remember that the local node has been cloned. The flag will be set on 'copy' as well.
8970-
tree->gtFlags |= GTF_VAR_CLONED;
8970+
tree->gtFlags |= GTF_VAR_MOREUSES;
89718971
copy = new (this, GT_LCL_FLD)
89728972
GenTreeLclFld(GT_LCL_FLD, tree->TypeGet(), tree->AsLclFld()->GetLclNum(),
89738973
tree->AsLclFld()->GetLclOffs(), tree->AsLclFld()->GetLayout());
@@ -9032,14 +9032,14 @@ GenTree* Compiler::gtCloneExpr(
90329032
{
90339033
case GT_STORE_LCL_VAR:
90349034
// Remember that the local node has been cloned. The flag will be set on 'copy' as well.
9035-
tree->gtFlags |= GTF_VAR_CLONED;
9035+
tree->gtFlags |= GTF_VAR_MOREUSES;
90369036
copy = new (this, GT_STORE_LCL_VAR)
90379037
GenTreeLclVar(tree->TypeGet(), tree->AsLclVar()->GetLclNum(), tree->AsLclVar()->Data());
90389038
break;
90399039

90409040
case GT_STORE_LCL_FLD:
90419041
// Remember that the local node has been cloned. The flag will be set on 'copy' as well.
9042-
tree->gtFlags |= GTF_VAR_CLONED;
9042+
tree->gtFlags |= GTF_VAR_MOREUSES;
90439043
copy = new (this, GT_STORE_LCL_FLD)
90449044
GenTreeLclFld(tree->TypeGet(), tree->AsLclFld()->GetLclNum(), tree->AsLclFld()->GetLclOffs(),
90459045
tree->AsLclFld()->Data(), tree->AsLclFld()->GetLayout());
@@ -16074,7 +16074,9 @@ GenTree* Compiler::gtNewRefCOMfield(GenTree* objPtr,
1607416074
// helper needs pointer to struct, not struct itself
1607516075
if (pFieldInfo->helper == CORINFO_HELP_SETFIELDSTRUCT)
1607616076
{
16077-
assg = impGetStructAddr(assg, CHECK_SPILL_ALL, true);
16077+
// TODO-Bug?: verify if flags matter here
16078+
GenTreeFlags indirFlags = GTF_EMPTY;
16079+
assg = impGetNodeAddr(assg, CHECK_SPILL_ALL, &indirFlags);
1607816080
}
1607916081
else if (lclTyp == TYP_DOUBLE && assg->TypeGet() == TYP_FLOAT)
1608016082
{
@@ -16149,8 +16151,10 @@ GenTree* Compiler::gtNewRefCOMfield(GenTree* objPtr,
1614916151
{
1615016152
if (!varTypeIsStruct(lclTyp))
1615116153
{
16152-
result = impGetStructAddr(result, CHECK_SPILL_ALL, true);
16153-
result = gtNewIndir(lclTyp, result);
16154+
// get the result as primitive type
16155+
GenTreeFlags indirFlags = GTF_EMPTY;
16156+
result = impGetNodeAddr(result, CHECK_SPILL_ALL, &indirFlags);
16157+
result = gtNewIndir(lclTyp, result, indirFlags);
1615416158
}
1615516159
}
1615616160
else if (varTypeIsSmall(lclTyp))

src/coreclr/jit/gentree.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ enum GenTreeFlags : unsigned int
453453
GTF_LIVENESS_MASK = GTF_VAR_DEF | GTF_VAR_USEASG | GTF_VAR_DEATH_MASK,
454454

455455
GTF_VAR_ITERATOR = 0x01000000, // GT_LCL_VAR -- this is a iterator reference in the loop condition
456-
GTF_VAR_CLONED = 0x00800000, // GT_LCL_VAR -- this node has been cloned or is a clone
456+
GTF_VAR_MOREUSES = 0x00800000, // GT_LCL_VAR -- this node has additonal uses, for example due to cloning
457457
GTF_VAR_CONTEXT = 0x00400000, // GT_LCL_VAR -- this node is part of a runtime lookup
458458
GTF_VAR_EXPLICIT_INIT = 0x00200000, // GT_LCL_VAR -- this node is an "explicit init" store. Valid until rationalization.
459459

@@ -491,8 +491,8 @@ enum GenTreeFlags : unsigned int
491491
GTF_IND_NONNULL = 0x00400000, // GT_IND -- the indirection never returns null (zero)
492492
GTF_IND_INITCLASS = 0x00200000, // OperIsIndir() -- the indirection requires preceding static cctor
493493

494-
GTF_IND_FLAGS = GTF_IND_VOLATILE | GTF_IND_NONFAULTING | GTF_IND_UNALIGNED | GTF_IND_INVARIANT |
495-
GTF_IND_NONNULL | GTF_IND_TGT_NOT_HEAP | GTF_IND_TGT_HEAP | GTF_IND_INITCLASS,
494+
GTF_IND_COPYABLE_FLAGS = GTF_IND_VOLATILE | GTF_IND_NONFAULTING | GTF_IND_UNALIGNED | GTF_IND_INITCLASS,
495+
GTF_IND_FLAGS = GTF_IND_COPYABLE_FLAGS | GTF_IND_NONNULL | GTF_IND_TGT_NOT_HEAP | GTF_IND_TGT_HEAP | GTF_IND_INVARIANT,
496496

497497
GTF_ADDRMODE_NO_CSE = 0x80000000, // GT_ADD/GT_MUL/GT_LSH -- Do not CSE this node only, forms complex
498498
// addressing mode

src/coreclr/jit/importer.cpp

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -807,8 +807,10 @@ GenTree* Compiler::impStoreStruct(GenTree* store,
807807
WellKnownArg wellKnownArgType =
808808
srcCall->ShouldHaveRetBufArg() ? WellKnownArg::RetBuffer : WellKnownArg::None;
809809

810-
GenTree* destAddr = impGetStructAddr(store, CHECK_SPILL_ALL, /* willDeref */ true);
811-
NewCallArg newArg = NewCallArg::Primitive(destAddr).WellKnown(wellKnownArgType);
810+
// TODO-Bug?: verify if flags matter here
811+
GenTreeFlags indirFlags = GTF_EMPTY;
812+
GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, &indirFlags);
813+
NewCallArg newArg = NewCallArg::Primitive(destAddr).WellKnown(wellKnownArgType);
812814

813815
#if !defined(TARGET_ARM)
814816
// 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,
909911
if (call->ShouldHaveRetBufArg())
910912
{
911913
// insert the return value buffer into the argument list as first byref parameter after 'this'
912-
GenTree* destAddr = impGetStructAddr(store, CHECK_SPILL_ALL, /* willDeref */ true);
914+
// TODO-Bug?: verify if flags matter here
915+
GenTreeFlags indirFlags = GTF_EMPTY;
916+
GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, &indirFlags);
913917
call->gtArgs.InsertAfterThisOrFirst(this,
914918
NewCallArg::Primitive(destAddr).WellKnown(WellKnownArg::RetBuffer));
915919

@@ -926,16 +930,17 @@ GenTree* Compiler::impStoreStruct(GenTree* store,
926930
{
927931
// Since we are assigning the result of a GT_MKREFANY, "destAddr" must point to a refany.
928932
// TODO-CQ: we can do this without address-exposing the local on the LHS.
929-
GenTree* destAddr = impGetStructAddr(store, CHECK_SPILL_ALL, /* willDeref */ true);
930-
GenTree* destAddrClone;
933+
GenTreeFlags indirFlags = GTF_EMPTY;
934+
GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, &indirFlags);
935+
GenTree* destAddrClone;
931936
destAddr = impCloneExpr(destAddr, &destAddrClone, curLevel, pAfterStmt DEBUGARG("MKREFANY assignment"));
932937

933938
assert(OFFSETOF__CORINFO_TypedReference__dataPtr == 0);
934939
assert(destAddr->gtType == TYP_I_IMPL || destAddr->gtType == TYP_BYREF);
935940

936941
// Append the store of the pointer value.
937942
// TODO-Bug: the pointer value can be a byref. Use its actual type here instead of TYP_I_IMPL.
938-
GenTree* ptrFieldStore = gtNewStoreIndNode(TYP_I_IMPL, destAddr, src->AsOp()->gtOp1);
943+
GenTree* ptrFieldStore = gtNewStoreIndNode(TYP_I_IMPL, destAddr, src->AsOp()->gtOp1, indirFlags);
939944
if (pAfterStmt)
940945
{
941946
Statement* newStmt = gtNewStmt(ptrFieldStore, usedDI);
@@ -1020,51 +1025,59 @@ GenTree* Compiler::impStoreStructPtr(GenTree* destAddr, GenTree* value, unsigned
10201025
}
10211026

10221027
//------------------------------------------------------------------------
1023-
// impGetStructAddr: Get the address of a struct value / location.
1028+
// impGetNodeAddr: Get the address of a value.
10241029
//
10251030
// Arguments:
1026-
// structVal - The value in question
1027-
// curLevel - Stack level for spilling
1028-
// willDeref - Whether the caller will dereference the address
1031+
// val - The value in question
1032+
// curLevel - Stack level for spilling
1033+
// pDerefFlags - Flags to be used on dereference, nullptr when
1034+
// the address won't be dereferenced. Returned flags
1035+
// are included in the GTF_IND_COPYABLE_FLAGS mask.
10291036
//
10301037
// Return Value:
1031-
// In case "structVal" can represent locations (is an indirection/local),
1038+
// In case "val" represents a location (is an indirection/local),
10321039
// will return its address. Otherwise, address of a temporary assigned
1033-
// the value of "structVal" will be returned.
1040+
// the value of "val" will be returned.
10341041
//
1035-
GenTree* Compiler::impGetStructAddr(GenTree* structVal, unsigned curLevel, bool willDeref)
1042+
GenTree* Compiler::impGetNodeAddr(GenTree* val, unsigned curLevel, GenTreeFlags* pDerefFlags)
10361043
{
1037-
assert(varTypeIsStruct(structVal));
1038-
switch (structVal->OperGet())
1044+
if (pDerefFlags != nullptr)
1045+
{
1046+
*pDerefFlags = GTF_EMPTY;
1047+
}
1048+
switch (val->OperGet())
10391049
{
10401050
case GT_BLK:
10411051
case GT_IND:
10421052
case GT_STOREIND:
10431053
case GT_STORE_BLK:
1044-
if (willDeref)
1054+
if (pDerefFlags != nullptr)
10451055
{
1046-
return structVal->AsIndir()->Addr();
1056+
*pDerefFlags = val->gtFlags & GTF_IND_COPYABLE_FLAGS;
1057+
return val->AsIndir()->Addr();
10471058
}
10481059
break;
10491060

10501061
case GT_LCL_VAR:
10511062
case GT_STORE_LCL_VAR:
1052-
return gtNewLclVarAddrNode(structVal->AsLclVar()->GetLclNum(), TYP_BYREF);
1063+
val->gtFlags |= GTF_VAR_MOREUSES;
1064+
return gtNewLclVarAddrNode(val->AsLclVar()->GetLclNum(), TYP_BYREF);
10531065

10541066
case GT_LCL_FLD:
10551067
case GT_STORE_LCL_FLD:
1056-
return gtNewLclAddrNode(structVal->AsLclFld()->GetLclNum(), structVal->AsLclFld()->GetLclOffs(), TYP_BYREF);
1068+
val->gtFlags |= GTF_VAR_MOREUSES;
1069+
return gtNewLclAddrNode(val->AsLclFld()->GetLclNum(), val->AsLclFld()->GetLclOffs(), TYP_BYREF);
10571070

10581071
case GT_COMMA:
1059-
impAppendTree(structVal->AsOp()->gtGetOp1(), curLevel, impCurStmtDI);
1060-
return impGetStructAddr(structVal->AsOp()->gtGetOp2(), curLevel, willDeref);
1072+
impAppendTree(val->AsOp()->gtGetOp1(), curLevel, impCurStmtDI);
1073+
return impGetNodeAddr(val->AsOp()->gtGetOp2(), curLevel, pDerefFlags);
10611074

10621075
default:
10631076
break;
10641077
}
10651078

10661079
unsigned lclNum = lvaGrabTemp(true DEBUGARG("location for address-of(RValue)"));
1067-
impStoreTemp(lclNum, structVal, curLevel);
1080+
impStoreTemp(lclNum, val, curLevel);
10681081

10691082
// The 'return value' is now address of the temp itself.
10701083
return gtNewLclVarAddrNode(lclNum, TYP_BYREF);
@@ -3000,7 +3013,9 @@ int Compiler::impBoxPatternMatch(CORINFO_RESOLVED_TOKEN* pResolvedToken,
30003013
GenTree* objToBox = impPopStack().val;
30013014

30023015
// Spill struct to get its address (to access hasValue field)
3003-
objToBox = impGetStructAddr(objToBox, CHECK_SPILL_ALL, true);
3016+
// TODO-Bug?: verify if flags matter here
3017+
GenTreeFlags indirFlags = GTF_EMPTY;
3018+
objToBox = impGetNodeAddr(objToBox, CHECK_SPILL_ALL, &indirFlags);
30043019

30053020
static_assert_no_msg(OFFSETOF__CORINFO_NullableOfT__hasValue == 0);
30063021
impPushOnStack(gtNewIndir(TYP_BOOL, objToBox), typeInfo(TYP_INT));
@@ -3348,7 +3363,9 @@ void Compiler::impImportAndPushBox(CORINFO_RESOLVED_TOKEN* pResolvedToken)
33483363
return;
33493364
}
33503365

3351-
op1 = gtNewHelperCallNode(boxHelper, TYP_REF, op2, impGetStructAddr(exprToBox, CHECK_SPILL_ALL, true));
3366+
// TODO-Bug?: verify if flags matter here
3367+
GenTreeFlags indirFlags = GTF_EMPTY;
3368+
op1 = gtNewHelperCallNode(boxHelper, TYP_REF, op2, impGetNodeAddr(exprToBox, CHECK_SPILL_ALL, &indirFlags));
33523369
}
33533370

33543371
/* Push the result back on the stack, */
@@ -7968,7 +7985,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
79687985
}
79697986
else
79707987
{
7971-
op1 = impGetStructAddr(op1, CHECK_SPILL_ALL, false);
7988+
op1 = impGetNodeAddr(op1, CHECK_SPILL_ALL, nullptr);
79727989
}
79737990

79747991
JITDUMP("\n ... optimized to ...\n");
@@ -8908,7 +8925,9 @@ void Compiler::impImportBlockCode(BasicBlock* block)
89088925
BADCODE3("Unexpected opcode (has to be LDFLD)", ": %02X", (int)opcode);
89098926
}
89108927

8911-
obj = impGetStructAddr(obj, CHECK_SPILL_ALL, true);
8928+
// TODO-Bug?: verify if flags matter here
8929+
GenTreeFlags indirFlags = GTF_EMPTY;
8930+
obj = impGetNodeAddr(obj, CHECK_SPILL_ALL, &indirFlags);
89128931
}
89138932

89148933
op1 = gtNewFieldAddrNode(resolvedToken.hField, obj, fieldInfo.offset);
@@ -9661,12 +9680,13 @@ void Compiler::impImportBlockCode(BasicBlock* block)
96619680
else
96629681
{
96639682
// Get the address of the refany
9664-
op1 = impGetStructAddr(op1, CHECK_SPILL_ALL, /* willDeref */ true);
9683+
GenTreeFlags indirFlags = GTF_EMPTY;
9684+
op1 = impGetNodeAddr(op1, CHECK_SPILL_ALL, &indirFlags);
96659685

96669686
// Fetch the type from the correct slot
96679687
op1 = gtNewOperNode(GT_ADD, TYP_BYREF, op1,
96689688
gtNewIconNode(OFFSETOF__CORINFO_TypedReference__type, TYP_I_IMPL));
9669-
op1 = gtNewIndir(TYP_BYREF, op1);
9689+
op1 = gtNewIndir(TYP_BYREF, op1, indirFlags);
96709690
}
96719691

96729692
// Convert native TypeHandle to RuntimeTypeHandle.

0 commit comments

Comments
 (0)