Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Physical VN -- fields
  • Loading branch information
SingleAccretion committed May 2, 2022
commit 9a59a6f42d2355257daa5b4a41d18271a34517c0
9 changes: 9 additions & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -4737,6 +4737,15 @@ class Compiler
ValueNumPair value,
bool normalize = true);

void fgValueNumberFieldLoad(GenTree* loadTree, GenTree* baseAddr, FieldSeqNode* fieldSeq, ssize_t offset);

void fgValueNumberFieldStore(GenTree* storeNode,
GenTree* baseAddr,
FieldSeqNode* fieldSeq,
ssize_t offset,
unsigned storeSize,
ValueNum value);

unsigned fgVNPassesCompleted; // Number of times fgValueNumber has been run.

// Utility functions for fgValueNumber.
Expand Down
36 changes: 26 additions & 10 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16760,6 +16760,7 @@ bool GenTreeIntConCommon::AddrNeedsReloc(Compiler* comp)
// comp - the Compiler object
// pBaseAddr - [out] parameter for "the base address"
// pFldSeq - [out] parameter for the field sequence
// pOffset - [out] parameter for the offset of the component struct fields
//
// Return Value:
// If "this" matches patterns denoted above, and the FldSeq found is "full",
Expand All @@ -16771,7 +16772,7 @@ bool GenTreeIntConCommon::AddrNeedsReloc(Compiler* comp)
// reference, for statics - the address to which the field offset with the
// field sequence is added, see "impImportStaticFieldAccess" and "fgMorphField".
//
bool GenTree::IsFieldAddr(Compiler* comp, GenTree** pBaseAddr, FieldSeqNode** pFldSeq)
bool GenTree::IsFieldAddr(Compiler* comp, GenTree** pBaseAddr, FieldSeqNode** pFldSeq, ssize_t* pOffset)
{
assert(TypeIs(TYP_I_IMPL, TYP_BYREF, TYP_REF));

Expand All @@ -16780,6 +16781,7 @@ bool GenTree::IsFieldAddr(Compiler* comp, GenTree** pBaseAddr, FieldSeqNode** pF

GenTree* baseAddr = nullptr;
FieldSeqNode* fldSeq = FieldSeqStore::NotAField();
ssize_t offset = 0;

if (OperIs(GT_ADD))
{
Expand All @@ -16788,14 +16790,16 @@ bool GenTree::IsFieldAddr(Compiler* comp, GenTree** pBaseAddr, FieldSeqNode** pF
if (AsOp()->gtOp1->IsCnsIntOrI() && AsOp()->gtOp1->IsIconHandle())
{
assert(!AsOp()->gtOp2->IsCnsIntOrI() || !AsOp()->gtOp2->IsIconHandle());
fldSeq = AsOp()->gtOp1->AsIntCon()->gtFieldSeq;
baseAddr = AsOp()->gtOp2;
fldSeq = AsOp()->gtOp1->AsIntCon()->gtFieldSeq;
offset = AsOp()->gtOp1->AsIntCon()->IconValue();
}
else if (AsOp()->gtOp2->IsCnsIntOrI())
{
assert(!AsOp()->gtOp1->IsCnsIntOrI() || !AsOp()->gtOp1->IsIconHandle());
fldSeq = AsOp()->gtOp2->AsIntCon()->gtFieldSeq;
baseAddr = AsOp()->gtOp1;
fldSeq = AsOp()->gtOp2->AsIntCon()->gtFieldSeq;
offset = AsOp()->gtOp2->AsIntCon()->IconValue();
}
else
{
Expand All @@ -16807,12 +16811,15 @@ bool GenTree::IsFieldAddr(Compiler* comp, GenTree** pBaseAddr, FieldSeqNode** pF
else if (IsCnsIntOrI() && IsIconHandle(GTF_ICON_STATIC_HDL))
{
assert(!comp->GetZeroOffsetFieldMap()->Lookup(this) && (AsIntCon()->gtFieldSeq != nullptr));
fldSeq = AsIntCon()->gtFieldSeq;
baseAddr = this;
baseAddr = this;
fldSeq = AsIntCon()->gtFieldSeq;
offset = AsIntCon()->IconValue();
}
else if (comp->GetZeroOffsetFieldMap()->Lookup(this, &fldSeq))
{
assert((fldSeq != FieldSeqStore::NotAField()) || (fldSeq->GetOffset() == 0));
baseAddr = this;
offset = 0;
}
else
{
Expand All @@ -16826,6 +16833,9 @@ bool GenTree::IsFieldAddr(Compiler* comp, GenTree** pBaseAddr, FieldSeqNode** pF
return false;
}

// Subtract from the offset such that the portion remaining is relative to the field itself.
offset -= fldSeq->GetOffset();

// The above screens out obviously invalid cases, but we have more checks to perform. The
// sequence returned from this method *must* start with either a class (NOT struct) field
// or a static field. To avoid the expense of calling "getFieldClass" here, we will instead
Expand All @@ -16840,6 +16850,7 @@ bool GenTree::IsFieldAddr(Compiler* comp, GenTree** pBaseAddr, FieldSeqNode** pF
}

*pFldSeq = fldSeq;
*pOffset = offset;
return true;
}

Expand All @@ -16849,6 +16860,7 @@ bool GenTree::IsFieldAddr(Compiler* comp, GenTree** pBaseAddr, FieldSeqNode** pF

*pBaseAddr = baseAddr;
*pFldSeq = fldSeq;
*pOffset = offset;
return true;
}

Expand Down Expand Up @@ -18117,16 +18129,17 @@ bool GenTree::IsArrayAddr(GenTreeArrAddr** pArrAddr)
// Note that the value of the below field doesn't matter; it exists only to provide a distinguished address.
//
// static
FieldSeqNode FieldSeqStore::s_notAField(nullptr, nullptr, FieldSeqNode::FieldKind::Instance);
FieldSeqNode FieldSeqStore::s_notAField(nullptr, nullptr, 0, FieldSeqNode::FieldKind::Instance);

// FieldSeqStore methods.
FieldSeqStore::FieldSeqStore(CompAllocator alloc) : m_alloc(alloc), m_canonMap(new (alloc) FieldSeqNodeCanonMap(alloc))
{
}

FieldSeqNode* FieldSeqStore::CreateSingleton(CORINFO_FIELD_HANDLE fieldHnd, FieldSeqNode::FieldKind fieldKind)
FieldSeqNode* FieldSeqStore::CreateSingleton(
CORINFO_FIELD_HANDLE fieldHnd, size_t offset, FieldSeqNode::FieldKind fieldKind)
{
FieldSeqNode fsn(fieldHnd, nullptr, fieldKind);
FieldSeqNode fsn(fieldHnd, nullptr, offset, fieldKind);
FieldSeqNode* res = nullptr;
if (m_canonMap->Lookup(fsn, &res))
{
Expand Down Expand Up @@ -18165,7 +18178,7 @@ FieldSeqNode* FieldSeqStore::Append(FieldSeqNode* a, FieldSeqNode* b)
assert(a != b);

FieldSeqNode* tmp = Append(a->GetNext(), b);
FieldSeqNode fsn(a->GetFieldHandleValue(), tmp, a->GetKind());
FieldSeqNode fsn(a->GetFieldHandleValue(), tmp, a->GetOffset(), a->GetKind());
FieldSeqNode* res = nullptr;
if (m_canonMap->Lookup(fsn, &res))
{
Expand All @@ -18181,7 +18194,9 @@ FieldSeqNode* FieldSeqStore::Append(FieldSeqNode* a, FieldSeqNode* b)
}
}

FieldSeqNode::FieldSeqNode(CORINFO_FIELD_HANDLE fieldHnd, FieldSeqNode* next, FieldKind fieldKind) : m_next(next)
FieldSeqNode::FieldSeqNode(CORINFO_FIELD_HANDLE fieldHnd, FieldSeqNode* next, size_t offset, FieldKind fieldKind)
: m_next(next)
, m_offset(offset)
{
uintptr_t handleValue = reinterpret_cast<uintptr_t>(fieldHnd);

Expand All @@ -18191,6 +18206,7 @@ FieldSeqNode::FieldSeqNode(CORINFO_FIELD_HANDLE fieldHnd, FieldSeqNode* next, Fi
if (fieldHnd != NO_FIELD_HANDLE)
{
assert(JitTls::GetCompiler()->eeIsFieldStatic(fieldHnd) == IsStaticField());
// TODO-PhysicalVN: assert that "offset" is correct.
}
else
{
Expand Down
21 changes: 18 additions & 3 deletions src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,9 +243,10 @@ class FieldSeqNode

uintptr_t m_fieldHandleAndKind;
FieldSeqNode* m_next;
size_t m_offset;

public:
FieldSeqNode(CORINFO_FIELD_HANDLE fieldHnd, FieldSeqNode* next, FieldKind fieldKind);
FieldSeqNode(CORINFO_FIELD_HANDLE fieldHnd, FieldSeqNode* next, size_t offset, FieldKind fieldKind);

FieldKind GetKind() const
{
Expand All @@ -268,6 +269,18 @@ class FieldSeqNode
return m_next;
}

//------------------------------------------------------------------------
// GetOffset: Retrieve "the offset" for the field this node represents.
//
// For statics with a known (constant) address it will be the value of that address.
// For boxed statics, it will be TARGET_POINTER_SIZE (the method table pointer size).
// For other fields, it will be equal to the value "getFieldOffset" would return.
//
size_t GetOffset() const
{
return m_offset;
}

bool IsStaticField() const
{
return (GetKind() == FieldKind::SimpleStatic) || (GetKind() == FieldKind::SharedStatic);
Expand All @@ -290,7 +303,8 @@ class FieldSeqNode

// Make sure this provides methods that allow it to be used as a KeyFuncs type in JitHashTable.
// Note that there is a one-to-one relationship between the field handle and the field kind, so
// we do not need to mask away the latter for comparison purposes.
// we do not need to mask away the latter for comparison purposes. Likewise, we do not need to
// include the offset.
static int GetHashCode(FieldSeqNode fsn)
{
return static_cast<int>(fsn.m_fieldHandleAndKind) ^ static_cast<int>(reinterpret_cast<intptr_t>(fsn.m_next));
Expand All @@ -317,6 +331,7 @@ class FieldSeqStore

// Returns the (canonical in the store) singleton field sequence for the given handle.
FieldSeqNode* CreateSingleton(CORINFO_FIELD_HANDLE fieldHnd,
size_t offset,
FieldSeqNode::FieldKind fieldKind = FieldSeqNode::FieldKind::Instance);

// This is a special distinguished FieldSeqNode indicating that a constant does *not*
Expand Down Expand Up @@ -1931,7 +1946,7 @@ struct GenTree
// Determine whether this tree is a basic block profile count update.
bool IsBlockProfileUpdate();

bool IsFieldAddr(Compiler* comp, GenTree** pBaseAddr, FieldSeqNode** pFldSeq);
bool IsFieldAddr(Compiler* comp, GenTree** pBaseAddr, FieldSeqNode** pFldSeq, ssize_t* pOffset);

bool IsArrayAddr(GenTreeArrAddr** pArrAddr);

Expand Down
45 changes: 34 additions & 11 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1410,11 +1410,14 @@ GenTree* Compiler::impAssignStructPtr(GenTree* destAddr,

assert(OFFSETOF__CORINFO_TypedReference__dataPtr == 0);
assert(destAddr->gtType == TYP_I_IMPL || destAddr->gtType == TYP_BYREF);
fgAddFieldSeqForZeroOffset(destAddr, GetFieldSeqStore()->CreateSingleton(GetRefanyDataField()));
fgAddFieldSeqForZeroOffset(destAddr,
GetFieldSeqStore()->CreateSingleton(GetRefanyDataField(),
OFFSETOF__CORINFO_TypedReference__dataPtr));

GenTree* ptrSlot = gtNewOperNode(GT_IND, TYP_I_IMPL, destAddr);
GenTreeIntCon* typeFieldOffset = gtNewIconNode(OFFSETOF__CORINFO_TypedReference__type, TYP_I_IMPL);
typeFieldOffset->gtFieldSeq = GetFieldSeqStore()->CreateSingleton(GetRefanyTypeField());
typeFieldOffset->gtFieldSeq = GetFieldSeqStore()->CreateSingleton(GetRefanyTypeField(),
OFFSETOF__CORINFO_TypedReference__type);
GenTree* typeSlot =
gtNewOperNode(GT_IND, TYP_I_IMPL, gtNewOperNode(GT_ADD, destAddr->gtType, destAddrClone, typeFieldOffset));

Expand Down Expand Up @@ -3635,11 +3638,11 @@ GenTree* Compiler::impCreateSpanIntrinsic(CORINFO_SIG_INFO* sig)
CORINFO_FIELD_HANDLE lengthFieldHnd = info.compCompHnd->getFieldInClass(spanHnd, 1);

GenTreeLclFld* pointerField = gtNewLclFldNode(spanTempNum, TYP_BYREF, 0);
pointerField->SetFieldSeq(GetFieldSeqStore()->CreateSingleton(pointerFieldHnd));
pointerField->SetFieldSeq(GetFieldSeqStore()->CreateSingleton(pointerFieldHnd, 0));
GenTree* pointerFieldAsg = gtNewAssignNode(pointerField, pointerValue);

GenTreeLclFld* lengthField = gtNewLclFldNode(spanTempNum, TYP_INT, TARGET_POINTER_SIZE);
lengthField->SetFieldSeq(GetFieldSeqStore()->CreateSingleton(lengthFieldHnd));
lengthField->SetFieldSeq(GetFieldSeqStore()->CreateSingleton(lengthFieldHnd, TARGET_POINTER_SIZE));
GenTree* lengthFieldAsg = gtNewAssignNode(lengthField, lengthValue);

// Now append a few statements the initialize the span
Expand Down Expand Up @@ -8164,11 +8167,35 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT
(pFieldInfo->fieldAccessor == CORINFO_FIELD_STATIC_READYTORUN_HELPER);
FieldSeqNode::FieldKind fieldKind =
isSharedStatic ? FieldSeqNode::FieldKind::SharedStatic : FieldSeqNode::FieldKind::SimpleStatic;
FieldSeqNode* innerFldSeq = !isBoxedStatic ? GetFieldSeqStore()->CreateSingleton(pResolvedToken->hField, fieldKind)
: FieldSeqStore::NotAField();

GenTree* op1;
FieldSeqNode* innerFldSeq = nullptr;
FieldSeqNode* outerFldSeq = nullptr;
if (isBoxedStatic)
{
innerFldSeq = FieldSeqStore::NotAField();
outerFldSeq = GetFieldSeqStore()->CreateSingleton(pResolvedToken->hField, TARGET_POINTER_SIZE, fieldKind);
}
else
{
bool hasConstAddr = (pFieldInfo->fieldAccessor == CORINFO_FIELD_STATIC_ADDRESS) ||
(pFieldInfo->fieldAccessor == CORINFO_FIELD_STATIC_RVA_ADDRESS);

size_t offset;
if (hasConstAddr)
{
offset = reinterpret_cast<size_t>(info.compCompHnd->getFieldAddress(pResolvedToken->hField));
assert(offset != 0);
}
else
{
offset = pFieldInfo->offset;
}

innerFldSeq = GetFieldSeqStore()->CreateSingleton(pResolvedToken->hField, offset, fieldKind);
outerFldSeq = FieldSeqStore::NotAField();
}

GenTree* op1;
switch (pFieldInfo->fieldAccessor)
{
case CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER:
Expand Down Expand Up @@ -8294,8 +8321,6 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT

if (isBoxedStatic)
{
FieldSeqNode* outerFldSeq = GetFieldSeqStore()->CreateSingleton(pResolvedToken->hField, fieldKind);

op1->ChangeType(TYP_REF); // points at boxed object
op1 = gtNewOperNode(GT_ADD, TYP_BYREF, op1, gtNewIconNode(TARGET_POINTER_SIZE, outerFldSeq));

Expand All @@ -8319,8 +8344,6 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT

if (isBoxedStatic)
{
FieldSeqNode* outerFldSeq = GetFieldSeqStore()->CreateSingleton(pResolvedToken->hField, fieldKind);

op1 = gtNewOperNode(GT_IND, TYP_REF, op1);
op1->gtFlags |= (GTF_IND_INVARIANT | GTF_IND_NONFAULTING | GTF_IND_NONNULL);

Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/jit/lclmorph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,8 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
if (haveCorrectFieldForVN)
{
FieldSeqStore* fieldSeqStore = compiler->GetFieldSeqStore();
m_fieldSeq = fieldSeqStore->Append(val.m_fieldSeq, fieldSeqStore->CreateSingleton(field->gtFldHnd));
FieldSeqNode* fieldSeqNode = fieldSeqStore->CreateSingleton(field->gtFldHnd, field->gtFldOffset);
m_fieldSeq = fieldSeqStore->Append(val.m_fieldSeq, fieldSeqNode);
}
else
{
Expand Down
45 changes: 23 additions & 22 deletions src/coreclr/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3465,9 +3465,11 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
// (tmp.ptr=argx),(tmp.type=handle)
GenTreeLclFld* destPtrSlot = gtNewLclFldNode(tmp, TYP_I_IMPL, OFFSETOF__CORINFO_TypedReference__dataPtr);
GenTreeLclFld* destTypeSlot = gtNewLclFldNode(tmp, TYP_I_IMPL, OFFSETOF__CORINFO_TypedReference__type);
destPtrSlot->SetFieldSeq(GetFieldSeqStore()->CreateSingleton(GetRefanyDataField()));
destPtrSlot->SetFieldSeq(GetFieldSeqStore()->CreateSingleton(GetRefanyDataField(),
OFFSETOF__CORINFO_TypedReference__dataPtr));
destPtrSlot->gtFlags |= GTF_VAR_DEF;
destTypeSlot->SetFieldSeq(GetFieldSeqStore()->CreateSingleton(GetRefanyTypeField()));
destTypeSlot->SetFieldSeq(GetFieldSeqStore()->CreateSingleton(GetRefanyTypeField(),
OFFSETOF__CORINFO_TypedReference__type));
destTypeSlot->gtFlags |= GTF_VAR_DEF;

GenTree* asgPtrSlot = gtNewAssignNode(destPtrSlot, argx->AsOp()->gtOp1);
Expand Down Expand Up @@ -5290,24 +5292,12 @@ GenTree* Compiler::fgMorphField(GenTree* tree, MorphAddrContext* mac)
{
assert(tree->gtOper == GT_FIELD);

CORINFO_FIELD_HANDLE symHnd = tree->AsField()->gtFldHnd;
unsigned fldOffset = tree->AsField()->gtFldOffset;
GenTree* objRef = tree->AsField()->GetFldObj();
bool objIsLocal = false;

FieldSeqNode* fieldSeq = FieldSeqStore::NotAField();
if (!tree->AsField()->gtFldMayOverlap)
{
if (objRef != nullptr)
{
fieldSeq = GetFieldSeqStore()->CreateSingleton(symHnd, FieldSeqNode::FieldKind::Instance);
}
else
{
// Only simple statics get imported as GT_FIELDs.
fieldSeq = GetFieldSeqStore()->CreateSingleton(symHnd, FieldSeqNode::FieldKind::SimpleStatic);
}
}
CORINFO_FIELD_HANDLE symHnd = tree->AsField()->gtFldHnd;
unsigned fldOffset = tree->AsField()->gtFldOffset;
GenTree* objRef = tree->AsField()->GetFldObj();
bool objIsLocal = false;
bool fldMayOverlap = tree->AsField()->gtFldMayOverlap;
FieldSeqNode* fieldSeq = FieldSeqStore::NotAField();

// Reset the flag because we may reuse the node.
tree->AsField()->gtFldMayOverlap = false;
Expand Down Expand Up @@ -5573,6 +5563,12 @@ GenTree* Compiler::fgMorphField(GenTree* tree, MorphAddrContext* mac)
addr = gtNewOperNode(GT_ADD, addType, addr, offsetNode);
}
#endif

if (!fldMayOverlap)
{
fieldSeq = GetFieldSeqStore()->CreateSingleton(symHnd, fldOffset, FieldSeqNode::FieldKind::Instance);
}

if (fldOffset != 0)
{
// Generate the "addr" node.
Expand Down Expand Up @@ -5687,6 +5683,9 @@ GenTree* Compiler::fgMorphField(GenTree* tree, MorphAddrContext* mac)
/* indirect to have tlsRef point at the base of the DLLs Thread Local Storage */
tlsRef = gtNewOperNode(GT_IND, TYP_I_IMPL, tlsRef);

assert(!fldMayOverlap);
fieldSeq = GetFieldSeqStore()->CreateSingleton(symHnd, fldOffset, FieldSeqNode::FieldKind::SimpleStatic);

if (fldOffset != 0)
{
GenTree* fldOffsetNode = new (this, GT_CNS_INT) GenTreeIntCon(TYP_INT, fldOffset, fieldSeq);
Expand Down Expand Up @@ -5721,9 +5720,11 @@ GenTree* Compiler::fgMorphField(GenTree* tree, MorphAddrContext* mac)
// For boxed statics, this direct address will be for the box. We have already added
// the indirection for the field itself and attached the sequence, in importation.
bool isBoxedStatic = gtIsStaticFieldPtrToBoxedStruct(tree->TypeGet(), symHnd);
if (isBoxedStatic)
if (!isBoxedStatic)
{
fieldSeq = FieldSeqStore::NotAField();
// Only simple statics get importred as GT_FIELDs.
fieldSeq = GetFieldSeqStore()->CreateSingleton(symHnd, reinterpret_cast<size_t>(fldAddr),
FieldSeqNode::FieldKind::SimpleStatic);
}

// TODO-CQ: enable this optimization for 32 bit targets.
Expand Down
Loading