Skip to content
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

JIT: Remove TYP_BLK and TYP_LCLBLK #83036

Merged
merged 21 commits into from
Mar 9, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3042,7 +3042,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
#if defined(UNIX_AMD64_ABI)
if (varTypeIsStruct(varDsc))
{
CORINFO_CLASS_HANDLE typeHnd = varDsc->GetStructHnd();
CORINFO_CLASS_HANDLE typeHnd = varDsc->GetLayout()->GetClassHandle();
assert(typeHnd != nullptr);
SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
compiler->eeGetSystemVAmd64PassStructInRegisterDescriptor(typeHnd, &structDesc);
Expand Down Expand Up @@ -3350,7 +3350,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
{
// This must be a SIMD type that's fully enregistered, but is passed as an HFA.
// Each field will be inserted into the same destination register.
assert(varTypeIsSIMD(varDsc) && !compiler->isOpaqueSIMDType(varDsc->GetStructHnd()));
assert(varTypeIsSIMD(varDsc) && !compiler->isOpaqueSIMDType(varDsc->GetLayout()));
assert(regArgTab[argNum].slot <= (int)varDsc->lvHfaSlots());
assert(argNum > 0);
assert(regArgTab[argNum - 1].varNum == varNum);
Expand Down
8 changes: 4 additions & 4 deletions src/coreclr/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6361,7 +6361,7 @@ void CodeGen::genJmpMethod(GenTree* jmp)
#if defined(UNIX_AMD64_ABI)
if (varTypeIsStruct(varDsc))
{
CORINFO_CLASS_HANDLE typeHnd = varDsc->GetStructHnd();
CORINFO_CLASS_HANDLE typeHnd = varDsc->GetLayout()->GetClassHandle();
assert(typeHnd != nullptr);

SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
Expand Down Expand Up @@ -6411,9 +6411,9 @@ void CodeGen::genJmpMethod(GenTree* jmp)
// Register argument
CLANG_FORMAT_COMMENT_ANCHOR;
#ifdef TARGET_X86
noway_assert(
isRegParamType(genActualType(varDsc->TypeGet())) ||
(varTypeIsStruct(varDsc->TypeGet()) && compiler->isTrivialPointerSizedStruct(varDsc->GetStructHnd())));
noway_assert(isRegParamType(genActualType(varDsc->TypeGet())) ||
((varDsc->TypeGet() == TYP_STRUCT) &&
compiler->isTrivialPointerSizedStruct(varDsc->GetLayout()->GetClassHandle())));
#else
noway_assert(isRegParamType(genActualType(varDsc->TypeGet())));
#endif // TARGET_X86
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10280,6 +10280,10 @@ void Compiler::EnregisterStats::RecordLocal(const LclVarDsc* varDsc)
m_stressPoisonImplicitByrefs++;
break;

case AddressExposedReason::EXTERNALLY_VISIBLE_IMPLICITLY:
m_externallyVisibleImplicitly++;
break;

default:
unreached();
break;
Expand Down Expand Up @@ -10376,5 +10380,6 @@ void Compiler::EnregisterStats::Dump(FILE* fout) const
PRINT_STATS(m_stressLclFld, m_addrExposed);
PRINT_STATS(m_dispatchRetBuf, m_addrExposed);
PRINT_STATS(m_stressPoisonImplicitByrefs, m_addrExposed);
PRINT_STATS(m_externallyVisibleImplicitly, m_addrExposed);
}
#endif // TRACK_ENREG_STATS
57 changes: 36 additions & 21 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,9 @@ enum class AddressExposedReason
STRESS_LCL_FLD, // Stress mode replaces localVar with localFld and makes them addrExposed.
DISPATCH_RET_BUF, // Caller return buffer dispatch.
STRESS_POISON_IMPLICIT_BYREFS, // This is an implicit byref we want to poison.
EXTERNALLY_VISIBLE_IMPLICITLY, // Local is visible externally without explicit escape in JIT IR.
// For example because it is used by GC or is the outgoing arg area
// that belongs to callees.
};

#endif // DEBUG
Expand Down Expand Up @@ -1082,6 +1085,7 @@ class LclVarDsc
lvStkOffs = offset;
}

// TODO-Cleanup: Remove this in favor of GetLayout()->Size/genTypeSize(lvType).
unsigned lvExactSize; // (exact) size of a STRUCT/SIMD/BLK local in bytes.

unsigned lvSize() const;
Expand All @@ -1090,25 +1094,9 @@ class LclVarDsc

unsigned lvSlotNum; // original slot # (if remapped)

// class handle for the local or null if not known or not a class,
// for a struct handle use `GetStructHnd()`.
// class handle for the local or null if not known or not a class
CORINFO_CLASS_HANDLE lvClassHnd;

// Get class handle for a struct local or implicitByRef struct local.
CORINFO_CLASS_HANDLE GetStructHnd() const
{
#ifdef FEATURE_SIMD
if (lvSIMDType && (m_layout == nullptr))
{
return NO_CLASS_HANDLE;
}
#endif

CORINFO_CLASS_HANDLE structHnd = GetLayout()->GetClassHandle();
assert(structHnd != NO_CLASS_HANDLE);
return structHnd;
}

private:
ClassLayout* m_layout; // layout info for structs

Expand Down Expand Up @@ -1191,6 +1179,16 @@ class LclVarDsc
m_layout = layout;
}

// Grow the size of a block layout local.
void GrowBlockLayout(ClassLayout* layout)
{
assert(varTypeIsStruct(lvType));
assert((m_layout == nullptr) || (m_layout->IsBlockLayout() && (m_layout->GetSize() <= layout->GetSize())));
assert(layout->IsBlockLayout());
m_layout = layout;
lvExactSize = layout->GetSize();
}

SsaDefArray<LclSsaVarDsc> lvPerSsaData;

// Returns the address of the per-Ssa data for the given ssaNum (which is required
Expand Down Expand Up @@ -3272,7 +3270,7 @@ class Compiler
// or if the inlinee has GC ref locals.

#if FEATURE_FIXED_OUT_ARGS
unsigned lvaOutgoingArgSpaceVar; // dummy TYP_LCLBLK var for fixed outgoing argument space
unsigned lvaOutgoingArgSpaceVar; // var that represents outgoing argument space
PhasedVar<unsigned> lvaOutgoingArgSpaceSize; // size of fixed outgoing argument space
#endif // FEATURE_FIXED_OUT_ARGS

Expand Down Expand Up @@ -3309,7 +3307,7 @@ class Compiler

#if !defined(FEATURE_EH_FUNCLETS)
// This is used for the callable handlers
unsigned lvaShadowSPslotsVar; // TYP_BLK variable for all the shadow SP slots
unsigned lvaShadowSPslotsVar; // Block-layout TYP_STRUCT variable for all the shadow SP slots
#endif // FEATURE_EH_FUNCLETS

int lvaCachedGenericContextArgOffs;
Expand Down Expand Up @@ -3520,7 +3518,7 @@ class Compiler
bool lvaIsMultiregStruct(LclVarDsc* varDsc, bool isVararg);

// If the local is a TYP_STRUCT, get/set a class handle describing it
CORINFO_CLASS_HANDLE lvaGetStruct(unsigned varNum);
void lvaSetStruct(unsigned varNum, ClassLayout* layout, bool unsafeValueClsCheck);
void lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool unsafeValueClsCheck);
void lvaSetStructUsedAsVarArg(unsigned varNum);

Expand Down Expand Up @@ -8715,14 +8713,30 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
return true;
}

bool isOpaqueSIMDType(ClassLayout* layout) const
{
if (layout->IsBlockLayout())
{
return true;
}

return isOpaqueSIMDType(layout->GetClassHandle());
}

// Returns true if the lclVar is an opaque SIMD type.
bool isOpaqueSIMDLclVar(const LclVarDsc* varDsc) const
{
if (!varDsc->lvSIMDType)
{
return false;
}
return isOpaqueSIMDType(varDsc->GetStructHnd());

if (varDsc->GetLayout() == nullptr)
{
return true;
}

return isOpaqueSIMDType(varDsc->GetLayout());
}

bool isNumericsNamespace(const char* ns)
Expand Down Expand Up @@ -10328,6 +10342,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
unsigned m_dispatchRetBuf;
unsigned m_wideIndir;
unsigned m_stressPoisonImplicitByrefs;
unsigned m_externallyVisibleImplicitly;

public:
void RecordLocal(const LclVarDsc* varDsc);
Expand Down
12 changes: 5 additions & 7 deletions src/coreclr/jit/flowgraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1894,9 +1894,8 @@ void Compiler::fgAddReversePInvokeEnterExit()

lvaReversePInvokeFrameVar = lvaGrabTempWithImplicitUse(false DEBUGARG("Reverse Pinvoke FrameVar"));

LclVarDsc* varDsc = lvaGetDesc(lvaReversePInvokeFrameVar);
varDsc->lvType = TYP_BLK;
varDsc->lvExactSize = eeGetEEInfo()->sizeOfReversePInvokeFrame;
LclVarDsc* varDsc = lvaGetDesc(lvaReversePInvokeFrameVar);
lvaSetStruct(lvaReversePInvokeFrameVar, typGetBlkLayout(eeGetEEInfo()->sizeOfReversePInvokeFrame), false);

// Add enter pinvoke exit callout at the start of prolog

Expand Down Expand Up @@ -2667,9 +2666,8 @@ PhaseStatus Compiler::fgAddInternal()
lvaSetVarAddrExposed(lvaInlinedPInvokeFrameVar DEBUGARG(AddressExposedReason::ESCAPE_ADDRESS));

LclVarDsc* varDsc = lvaGetDesc(lvaInlinedPInvokeFrameVar);
varDsc->lvType = TYP_BLK;
// Make room for the inlined frame.
varDsc->lvExactSize = eeGetEEInfo()->inlinedCallFrameInfo.size;
lvaSetStruct(lvaInlinedPInvokeFrameVar, typGetBlkLayout(eeGetEEInfo()->inlinedCallFrameInfo.size), false);
#if FEATURE_FIXED_OUT_ARGS
// Grab and reserve space for TCB, Frame regs used in PInvoke epilog to pop the inlined frame.
// See genPInvokeMethodEpilog() for use of the grabbed var. This is only necessary if we are
Expand All @@ -2678,8 +2676,7 @@ PhaseStatus Compiler::fgAddInternal()
{
lvaPInvokeFrameRegSaveVar = lvaGrabTempWithImplicitUse(false DEBUGARG("PInvokeFrameRegSave Var"));
varDsc = lvaGetDesc(lvaPInvokeFrameRegSaveVar);
varDsc->lvType = TYP_BLK;
varDsc->lvExactSize = 2 * REGSIZE_BYTES;
lvaSetStruct(lvaPInvokeFrameRegSaveVar, typGetBlkLayout(2 * REGSIZE_BYTES), false);
}
#endif
}
Expand Down Expand Up @@ -3043,6 +3040,7 @@ PhaseStatus Compiler::fgSimpleLowering()
// attempt later will cause an assert.
lvaOutgoingArgSpaceSize = outgoingArgSpaceSize;
lvaOutgoingArgSpaceSize.MarkAsReadOnly();
lvaGetDesc(lvaOutgoingArgSpaceVar)->GrowBlockLayout(typGetBlkLayout(outgoingArgSpaceSize));

#endif // FEATURE_FIXED_OUT_ARGS

Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/jit/gcencode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4183,7 +4183,8 @@ void GCInfo::gcMakeRegPtrTable(

// If this is a TYP_STRUCT, handle its GC pointers.
// Note that the enregisterable struct types cannot have GC pointers in them.
if ((varDsc->TypeGet() == TYP_STRUCT) && varDsc->lvOnFrame && (varDsc->lvExactSize >= TARGET_POINTER_SIZE))
if ((varDsc->TypeGet() == TYP_STRUCT) && varDsc->GetLayout()->HasGCPtr() && varDsc->lvOnFrame &&
(varDsc->lvExactSize >= TARGET_POINTER_SIZE))
{
ClassLayout* layout = varDsc->GetLayout();
unsigned slots = layout->GetSlotCount();
Expand Down
77 changes: 25 additions & 52 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11302,27 +11302,6 @@ void Compiler::gtDispLclVarStructType(unsigned lclNum)
assert(layout != nullptr);
gtDispClassLayout(layout, type);
}
else if (type == TYP_LCLBLK)
{
#if FEATURE_FIXED_OUT_ARGS
assert(lclNum == lvaOutgoingArgSpaceVar);
// Since lvaOutgoingArgSpaceSize is a PhasedVar we can't read it for Dumping until
// after we set it to something.
if (lvaOutgoingArgSpaceSize.HasFinalValue())
{
// A PhasedVar<T> can't be directly used as an arg to a variadic function
unsigned value = lvaOutgoingArgSpaceSize;
printf("<%u> ", value);
}
else
{
printf("<na> "); // The value hasn't yet been determined
}
#else
assert(!"Unknown size");
NO_WAY("Target doesn't support TYP_LCLBLK");
#endif // FEATURE_FIXED_OUT_ARGS
}
}

#if defined(DEBUG) && defined(TARGET_ARM64)
Expand Down Expand Up @@ -11719,7 +11698,7 @@ void Compiler::gtDispLeaf(GenTree* tree, IndentStack* indentStack)
else
#endif // !defined(TARGET_64BIT)
{
CORINFO_CLASS_HANDLE typeHnd = varDsc->GetStructHnd();
CORINFO_CLASS_HANDLE typeHnd = varDsc->GetLayout()->GetClassHandle();
CORINFO_FIELD_HANDLE fldHnd =
info.compCompHnd->getFieldInClass(typeHnd, fieldVarDsc->lvFldOrdinal);
fieldName = eeGetFieldName(fldHnd, true, buffer, sizeof(buffer));
Expand Down Expand Up @@ -15813,6 +15792,21 @@ GenTree* Compiler::gtNewTempAssign(
if (dstTyp == TYP_UNDEF)
{
varDsc->lvType = dstTyp = genActualType(valTyp);

if (varTypeIsStruct(dstTyp))
{
if (varTypeIsSIMD(dstTyp))
{
varDsc->lvExactSize = genTypeSize(dstTyp);
#ifdef FEATURE_SIMD
varDsc->lvSIMDType = 1;
#endif
}
else
{
lvaSetStruct(tmp, val->GetLayout(this), false);
}
}
}

#if FEATURE_SIMD
Expand Down Expand Up @@ -15880,40 +15874,13 @@ GenTree* Compiler::gtNewTempAssign(
GenTree* asg;
GenTree* dest = gtNewLclvNode(tmp, dstTyp);

// With first-class structs, we should be propagating the class handle on all non-primitive
// struct types. We don't have a convenient way to do that for all SIMD temps, since some
// internal trees use SIMD types that are not used by the input IL. In this case, we allow
// a null type handle and derive the necessary information about the type from its varType.
CORINFO_CLASS_HANDLE valStructHnd = gtGetStructHandleIfPresent(val);
if (varTypeIsStruct(varDsc) && (valStructHnd == NO_CLASS_HANDLE) && !varTypeIsSIMD(valTyp))
{
// There are some cases where we do not have a struct handle on the return value:
// 1. Handle-less BLK/LCL_FLD nodes.
// 2. The zero constant created by local assertion propagation.
// In these cases, we can use the type of the local for the assignment.
assert(val->gtEffectiveVal(true)->OperIs(GT_IND, GT_BLK, GT_LCL_FLD, GT_CNS_INT));
valStructHnd = lvaGetDesc(tmp)->GetStructHnd();
assert(valStructHnd != NO_CLASS_HANDLE);
}

if ((valStructHnd != NO_CLASS_HANDLE) && val->IsConstInitVal())
if (val->IsConstInitVal())
{
asg = gtNewAssignNode(dest, val);
}
else if (varTypeIsStruct(varDsc) && ((valStructHnd != NO_CLASS_HANDLE) || varTypeIsSIMD(valTyp)))
else if (varTypeIsStruct(varDsc))
{
// The struct value may be be a child of a GT_COMMA due to explicit null checks of indirs/fields.
GenTree* valx = val->gtEffectiveVal(/*commaOnly*/ true);

if (valStructHnd != NO_CLASS_HANDLE)
{
lvaSetStruct(tmp, valStructHnd, false);
}
else
{
assert(valx->gtOper != GT_OBJ);
}

valx->gtFlags |= GTF_DONT_CSE;
asg = impAssignStruct(dest, val, CHECK_SPILL_NONE, pAfterStmt, di, block);
}
Expand Down Expand Up @@ -17705,8 +17672,14 @@ CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleIfPresent(GenTree* tree)
}
break;
case GT_LCL_VAR:
structHnd = lvaGetDesc(tree->AsLclVar())->GetStructHnd();
{
LclVarDsc* dsc = lvaGetDesc(tree->AsLclVar());
if ((dsc->GetLayout() != nullptr) && !dsc->GetLayout()->IsBlockLayout())
{
structHnd = dsc->GetLayout()->GetClassHandle();
}
break;
}
case GT_RETURN:
structHnd = gtGetStructHandleIfPresent(tree->AsOp()->gtOp1);
break;
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/gschecks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ void Compiler::gsParamsToShadows()
{
// We don't need unsafe value cls check here since we are copying the params and this flag
// would have been set on the original param before reaching here.
lvaSetStruct(shadowVarNum, varDsc->GetStructHnd(), false);
lvaSetStruct(shadowVarNum, varDsc->GetLayout(), false);
shadowVarDsc->lvIsMultiRegArg = varDsc->lvIsMultiRegArg;
shadowVarDsc->lvIsMultiRegRet = varDsc->lvIsMultiRegRet;
}
Expand Down
Loading