Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -4855,7 +4855,7 @@ class Compiler
bool impIsLegalRetBuf(GenTree* retBuf, GenTreeCall* call);
GenTree* impStoreStructPtr(GenTree* destAddr, GenTree* value, unsigned curLevel, GenTreeFlags indirFlags = GTF_EMPTY);

GenTree* impGetNodeAddr(GenTree* val, unsigned curLevel, GenTreeFlags* pDerefFlags);
GenTree* impGetNodeAddr(GenTree* val, unsigned curLevel, GenTreeFlags allowedMustPreserveIndirFlags, GenTreeFlags* pIndirFlags);

var_types impNormStructType(CORINFO_CLASS_HANDLE structHnd, var_types* simdBaseType = nullptr);

Expand Down
7 changes: 6 additions & 1 deletion src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,12 @@ enum GenTreeFlags : unsigned
GTF_IND_INITCLASS = 0x00200000, // OperIsIndir() -- the indirection requires preceding static cctor
GTF_IND_ALLOW_NON_ATOMIC = 0x00100000, // GT_IND -- this memory access does not need to be atomic

GTF_IND_COPYABLE_FLAGS = GTF_IND_VOLATILE | GTF_IND_NONFAULTING | GTF_IND_UNALIGNED | GTF_IND_INITCLASS,
// Represents flags that an indirection based on another indirection must preserve
GTF_IND_MUST_PRESERVE_FLAGS = GTF_IND_VOLATILE | GTF_IND_UNALIGNED | GTF_IND_INITCLASS,

// Represents flags that an indirection based on another indirection can and must preserve
GTF_IND_COPYABLE_FLAGS = GTF_IND_MUST_PRESERVE_FLAGS | GTF_IND_NONFAULTING,

GTF_IND_FLAGS = GTF_IND_COPYABLE_FLAGS | GTF_IND_NONNULL | GTF_IND_TGT_NOT_HEAP | GTF_IND_TGT_HEAP | GTF_IND_INVARIANT | GTF_IND_ALLOW_NON_ATOMIC,

GTF_ADDRMODE_NO_CSE = 0x80000000, // GT_ADD/GT_MUL/GT_LSH -- Do not CSE this node only, forms complex
Expand Down
78 changes: 45 additions & 33 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -805,13 +805,14 @@ GenTree* Compiler::impStoreStruct(GenTree* store,
WellKnownArg wellKnownArgType =
srcCall->ShouldHaveRetBufArg() ? WellKnownArg::RetBuffer : WellKnownArg::None;

// TODO-Bug?: verify if flags matter here
// Return buffers cannot have volatile, unaligned, or initclass flags
GenTreeFlags indirFlags = GTF_EMPTY;
GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, &indirFlags);
GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, GTF_IND_MUST_PRESERVE_FLAGS, &indirFlags);

if (!impIsLegalRetBuf(destAddr, srcCall))
if (((indirFlags & GTF_IND_MUST_PRESERVE_FLAGS) != GTF_EMPTY) || !impIsLegalRetBuf(destAddr, srcCall))
Comment on lines +808 to +812
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// Return buffers cannot have volatile, unaligned, or initclass flags
GenTreeFlags indirFlags = GTF_EMPTY;
GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, &indirFlags);
GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, GTF_IND_MUST_PRESERVE_FLAGS, &indirFlags);
if (!impIsLegalRetBuf(destAddr, srcCall))
if (((indirFlags & GTF_IND_MUST_PRESERVE_FLAGS) != GTF_EMPTY) || !impIsLegalRetBuf(destAddr, srcCall))
GenTreeFlags indirFlags = GTF_EMPTY;
GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, GTF_IND_MUST_PRESERVE_FLAGS, &indirFlags);
// Return buffers cannot have volatile, unaligned, or initclass flags
if (((indirFlags & GTF_IND_MUST_PRESERVE_FLAGS) != GTF_EMPTY) || !impIsLegalRetBuf(destAddr, srcCall))

{
unsigned tmp = lvaGrabTemp(false DEBUGARG("stack copy for value returned via return buffer"));
unsigned tmp = lvaGrabTemp(false DEBUGARG(
printfAlloc("stack copy for value returned via return buffer for flags %x", (unsigned)indirFlags)));
lvaSetStruct(tmp, srcCall->gtRetClsHnd, false);

GenTree* spilledCall = gtNewStoreLclVarNode(tmp, srcCall);
Expand Down Expand Up @@ -929,13 +930,14 @@ GenTree* Compiler::impStoreStruct(GenTree* store,
if (call->ShouldHaveRetBufArg())
{
// insert the return value buffer into the argument list as first byref parameter after 'this'
// TODO-Bug?: verify if flags matter here
// Return buffers cannot have volatile, unaligned, or initclass flags
GenTreeFlags indirFlags = GTF_EMPTY;
GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, &indirFlags);
GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, GTF_IND_MUST_PRESERVE_FLAGS, &indirFlags);

if (!impIsLegalRetBuf(destAddr, call))
if (((indirFlags & GTF_IND_MUST_PRESERVE_FLAGS) != GTF_EMPTY) || !impIsLegalRetBuf(destAddr, call))
Comment on lines +933 to +937
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// Return buffers cannot have volatile, unaligned, or initclass flags
GenTreeFlags indirFlags = GTF_EMPTY;
GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, &indirFlags);
GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, GTF_IND_MUST_PRESERVE_FLAGS, &indirFlags);
if (!impIsLegalRetBuf(destAddr, call))
if (((indirFlags & GTF_IND_MUST_PRESERVE_FLAGS) != GTF_EMPTY) || !impIsLegalRetBuf(destAddr, call))
GenTreeFlags indirFlags = GTF_EMPTY;
GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, GTF_IND_MUST_PRESERVE_FLAGS, &indirFlags);
// Return buffers cannot have volatile, unaligned, or initclass flags
if (((indirFlags & GTF_IND_MUST_PRESERVE_FLAGS) != GTF_EMPTY) || !impIsLegalRetBuf(destAddr, call))

{
unsigned tmp = lvaGrabTemp(false DEBUGARG("stack copy for value returned via return buffer"));
unsigned tmp = lvaGrabTemp(false DEBUGARG(
printfAlloc("stack copy for value returned via return buffer for flags %x", (unsigned)indirFlags)));
lvaSetStruct(tmp, call->gtRetClsHnd, false);
destAddr = gtNewLclVarAddrNode(tmp, TYP_I_IMPL);

Expand Down Expand Up @@ -1096,35 +1098,38 @@ GenTree* Compiler::impStoreStructPtr(GenTree* destAddr, GenTree* value, unsigned
// impGetNodeAddr: Get the address of a value.
//
// Arguments:
// 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.
// val - The value in question
// curLevel - Stack level for spilling
// allowedMustPreserveIndirFlags - If 'val' is an indirection and it has any must-preserve indir flags (like
// volatile), then those flags must be included in this mask to be allowed
// through without creating a temp.
// pIndirFlags - [out] Flags that indirs created based on this address can and should set.
// Returned flags are included in the GTF_IND_COPYABLE_FLAGS mask.
//
// Return Value:
// In case "val" represents a location (is an indirection/local),
// will return its address. Otherwise, address of a temporary assigned
// the value of "val" will be returned.
//
GenTree* Compiler::impGetNodeAddr(GenTree* val, unsigned curLevel, GenTreeFlags* pDerefFlags)
GenTree* Compiler::impGetNodeAddr(GenTree* val,
unsigned curLevel,
GenTreeFlags allowedMustPreserveIndirFlags,
GenTreeFlags* pIndirFlags)
{
if (pDerefFlags != nullptr)
{
*pDerefFlags = GTF_EMPTY;
}
*pIndirFlags = GTF_EMPTY;
switch (val->OperGet())
{
case GT_BLK:
case GT_IND:
case GT_STOREIND:
case GT_STORE_BLK:
if (pDerefFlags != nullptr)
if (((val->gtFlags & GTF_IND_MUST_PRESERVE_FLAGS & ~allowedMustPreserveIndirFlags) != 0))
{
*pDerefFlags = val->gtFlags & GTF_IND_COPYABLE_FLAGS;
return val->AsIndir()->Addr();
break;
}
break;

*pIndirFlags = val->gtFlags & GTF_IND_COPYABLE_FLAGS;
return val->AsIndir()->Addr();

case GT_LCL_VAR:
case GT_STORE_LCL_VAR:
Expand All @@ -1138,12 +1143,13 @@ GenTree* Compiler::impGetNodeAddr(GenTree* val, unsigned curLevel, GenTreeFlags*

case GT_COMMA:
impAppendTree(val->AsOp()->gtGetOp1(), curLevel, impCurStmtDI);
return impGetNodeAddr(val->AsOp()->gtGetOp2(), curLevel, pDerefFlags);
return impGetNodeAddr(val->AsOp()->gtGetOp2(), curLevel, allowedMustPreserveIndirFlags, pIndirFlags);

default:
break;
}

assert(!val->OperIsStore());
unsigned lclNum = lvaGrabTemp(true DEBUGARG("location for address-of(RValue)"));
impStoreToTemp(lclNum, val, curLevel);

Expand Down Expand Up @@ -3290,12 +3296,13 @@ int Compiler::impBoxPatternMatch(CORINFO_RESOLVED_TOKEN* pResolvedToken,
GenTree* objToBox = impPopStack().val;

// Spill struct to get its address (to access hasValue field)
// TODO-Bug?: verify if flags matter here
// Transfer any volatile/unaligned flags to the indirection
GenTreeFlags indirFlags = GTF_EMPTY;
objToBox = impGetNodeAddr(objToBox, CHECK_SPILL_ALL, &indirFlags);
objToBox =
impGetNodeAddr(objToBox, CHECK_SPILL_ALL, GTF_IND_MUST_PRESERVE_FLAGS, &indirFlags);

static_assert(OFFSETOF__CORINFO_NullableOfT__hasValue == 0);
impPushOnStack(gtNewIndir(TYP_UBYTE, objToBox), typeInfo(TYP_INT));
impPushOnStack(gtNewIndir(TYP_UBYTE, objToBox, indirFlags), typeInfo(TYP_INT));

JITDUMP("\n Importing BOX; ISINST; BR_TRUE/FALSE as nullableVT.hasValue\n");
return returnToken;
Expand Down Expand Up @@ -3675,9 +3682,10 @@ void Compiler::impImportAndPushBox(CORINFO_RESOLVED_TOKEN* pResolvedToken)
return;
}

// TODO-Bug?: verify if flags matter here
// Boxing helpers cannot accept addresses with volatile, unaligned, or initclass flags
GenTreeFlags indirFlags = GTF_EMPTY;
op1 = gtNewHelperCallNode(boxHelper, TYP_REF, op2, impGetNodeAddr(exprToBox, CHECK_SPILL_ALL, &indirFlags));
op1 = gtNewHelperCallNode(boxHelper, TYP_REF, op2,
impGetNodeAddr(exprToBox, CHECK_SPILL_ALL, GTF_IND_INITCLASS, &indirFlags));
}

/* Push the result back on the stack, */
Expand Down Expand Up @@ -8526,7 +8534,8 @@ void Compiler::impImportBlockCode(BasicBlock* block)
}
else
{
op1 = impGetNodeAddr(op1, CHECK_SPILL_ALL, nullptr);
GenTreeFlags indirFlags;
op1 = impGetNodeAddr(op1, CHECK_SPILL_ALL, GTF_EMPTY, &indirFlags);
}

JITDUMP("\n ... optimized to ...\n");
Expand Down Expand Up @@ -9537,9 +9546,12 @@ void Compiler::impImportBlockCode(BasicBlock* block)
BADCODE3("Unexpected opcode (has to be LDFLD)", ": %02X", (int)opcode);
}

// TODO-Bug?: verify if flags matter here
GenTreeFlags indirFlags = GTF_EMPTY;
obj = impGetNodeAddr(obj, CHECK_SPILL_ALL, &indirFlags);
// Get the address and any flags from the original access (volatile, unaligned, etc.)
GenTreeFlags objAddrFlags = GTF_EMPTY;
obj = impGetNodeAddr(obj, CHECK_SPILL_ALL, GTF_IND_MUST_PRESERVE_FLAGS, &objAddrFlags);

// Combine the flags from the object address with any prefix flags
indirFlags |= objAddrFlags;
}

op1 = gtNewFieldAddrNode(resolvedToken.hField, obj, fieldInfo.offset);
Expand Down Expand Up @@ -10349,7 +10361,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)

// Get the address of the refany
GenTreeFlags indirFlags = GTF_EMPTY;
op1 = impGetNodeAddr(op1, CHECK_SPILL_ALL, &indirFlags);
op1 = impGetNodeAddr(op1, CHECK_SPILL_ALL, GTF_IND_MUST_PRESERVE_FLAGS, &indirFlags);

// Fetch the type from the correct slot
op1 = gtNewOperNode(GT_ADD, TYP_BYREF, op1,
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/importercalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5357,7 +5357,7 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic,
}
else
{
addr = impGetNodeAddr(op1, CHECK_SPILL_ALL, &indirFlags);
addr = impGetNodeAddr(op1, CHECK_SPILL_ALL, GTF_IND_MUST_PRESERVE_FLAGS, &indirFlags);
}

if (info.compCompHnd->getClassAlignmentRequirement(fromTypeHnd) <
Expand Down
Loading