Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Commit

Permalink
Pull struct type info out of GenTreeObj
Browse files Browse the repository at this point in the history
  • Loading branch information
mikedn committed Dec 29, 2018
1 parent 47c5949 commit 835f679
Show file tree
Hide file tree
Showing 27 changed files with 523 additions and 626 deletions.
37 changes: 12 additions & 25 deletions src/jit/codegenarm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)

// This GenTree node has data about GC pointers, this means we're dealing
// with CpObj.
assert(cpObjNode->gtGcPtrCount > 0);
assert(cpObjNode->gtLayout->HasGCPtr());
#endif // DEBUG

// Consume the operands and get them into the right registers.
Expand All @@ -731,29 +731,18 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
instGen_MemoryBarrier();
}

unsigned slots = cpObjNode->gtSlots;
unsigned slots = cpObjNode->gtLayout->GetSlotCount();
emitter* emit = getEmitter();

BYTE* gcPtrs = cpObjNode->gtGcPtrs;
StructTypeLayout* layout = cpObjNode->gtLayout;

// If we can prove it's on the stack we don't need to use the write barrier.
emitAttr attr = EA_PTRSIZE;
if (dstOnStack)
{
for (unsigned i = 0; i < slots; ++i)
{
if (gcPtrs[i] == GCT_GCREF)
{
attr = EA_GCREF;
}
else if (gcPtrs[i] == GCT_BYREF)
{
attr = EA_BYREF;
}
else
{
attr = EA_PTRSIZE;
}
var_types type = Compiler::getJitGCType(layout->GetGCPtr(i));
emitAttr attr = emitTypeSize(type);

emit->emitIns_R_R_I(INS_ldr, attr, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
INS_FLAGS_DONT_CARE, INS_OPTS_LDST_POST_INC);
Expand All @@ -763,30 +752,28 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
}
else
{
unsigned gcPtrCount = cpObjNode->gtGcPtrCount;

unsigned i = 0;
unsigned gcPtrCount = 0;
unsigned i = 0;
while (i < slots)
{
switch (gcPtrs[i])
switch (layout->GetGCPtr(i))
{
case TYPE_GC_NONE:
emit->emitIns_R_R_I(INS_ldr, attr, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
emit->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
INS_FLAGS_DONT_CARE, INS_OPTS_LDST_POST_INC);
emit->emitIns_R_R_I(INS_str, attr, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
emit->emitIns_R_R_I(INS_str, EA_PTRSIZE, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
INS_FLAGS_DONT_CARE, INS_OPTS_LDST_POST_INC);
break;

default:
// In the case of a GC-Pointer we'll call the ByRef write barrier helper
genEmitHelperCall(CORINFO_HELP_ASSIGN_BYREF, 0, EA_PTRSIZE);

gcPtrCount--;
gcPtrCount++;
break;
}
++i;
}
assert(gcPtrCount == 0);
assert(gcPtrCount == cpObjNode->gtLayout->GetGCPtrCount());
}

if (cpObjNode->gtFlags & GTF_BLK_VOLATILE)
Expand Down
26 changes: 12 additions & 14 deletions src/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2457,7 +2457,7 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)

// This GenTree node has data about GC pointers, this means we're dealing
// with CpObj.
assert(cpObjNode->gtGcPtrCount > 0);
assert(cpObjNode->gtLayout->HasGCPtr());
#endif // DEBUG

// Consume the operands and get them into the right registers.
Expand All @@ -2466,7 +2466,7 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
gcInfo.gcMarkRegPtrVal(REG_WRITE_BARRIER_SRC_BYREF, srcAddrType);
gcInfo.gcMarkRegPtrVal(REG_WRITE_BARRIER_DST_BYREF, dstAddr->TypeGet());

unsigned slots = cpObjNode->gtSlots;
unsigned slots = cpObjNode->gtLayout->GetSlotCount();

// Temp register(s) used to perform the sequence of loads and stores.
regNumber tmpReg = cpObjNode->ExtractTempReg();
Expand All @@ -2493,7 +2493,7 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)

emitter* emit = getEmitter();

BYTE* gcPtrs = cpObjNode->gtGcPtrs;
StructTypeLayout* layout = cpObjNode->gtLayout;

// If we can prove it's on the stack we don't need to use the write barrier.
if (dstOnStack)
Expand All @@ -2502,8 +2502,8 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
// Check if two or more remaining slots and use a ldp/stp sequence
while (i < slots - 1)
{
emitAttr attr0 = emitTypeSize(compiler->getJitGCType(gcPtrs[i + 0]));
emitAttr attr1 = emitTypeSize(compiler->getJitGCType(gcPtrs[i + 1]));
emitAttr attr0 = emitTypeSize(compiler->getJitGCType(layout->GetGCPtr(i + 0)));
emitAttr attr1 = emitTypeSize(compiler->getJitGCType(layout->GetGCPtr(i + 1)));

emit->emitIns_R_R_R_I(INS_ldp, attr0, tmpReg, tmpReg2, REG_WRITE_BARRIER_SRC_BYREF, 2 * TARGET_POINTER_SIZE,
INS_OPTS_POST_INDEX, attr1);
Expand All @@ -2515,7 +2515,7 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
// Use a ldr/str sequence for the last remainder
if (i < slots)
{
emitAttr attr0 = emitTypeSize(compiler->getJitGCType(gcPtrs[i + 0]));
emitAttr attr0 = emitTypeSize(compiler->getJitGCType(layout->GetGCPtr(i + 0)));

emit->emitIns_R_R_I(INS_ldr, attr0, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
INS_OPTS_POST_INDEX);
Expand All @@ -2525,16 +2525,15 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
}
else
{
unsigned gcPtrCount = cpObjNode->gtGcPtrCount;

unsigned i = 0;
unsigned gcPtrCount = 0;
unsigned i = 0;
while (i < slots)
{
switch (gcPtrs[i])
switch (layout->GetGCPtr(i))
{
case TYPE_GC_NONE:
// Check if the next slot's type is also TYP_GC_NONE and use ldp/stp
if ((i + 1 < slots) && (gcPtrs[i + 1] == TYPE_GC_NONE))
if ((i + 1 < slots) && (layout->GetGCPtr(i + 1) == TYPE_GC_NONE))
{
emit->emitIns_R_R_R_I(INS_ldp, EA_8BYTE, tmpReg, tmpReg2, REG_WRITE_BARRIER_SRC_BYREF,
2 * TARGET_POINTER_SIZE, INS_OPTS_POST_INDEX);
Expand All @@ -2554,13 +2553,12 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
default:
// In the case of a GC-Pointer we'll call the ByRef write barrier helper
genEmitHelperCall(CORINFO_HELP_ASSIGN_BYREF, 0, EA_PTRSIZE);

gcPtrCount--;
gcPtrCount++;
break;
}
++i;
}
assert(gcPtrCount == 0);
assert(gcPtrCount == cpObjNode->gtLayout->GetGCPtrCount());
}

if (cpObjNode->gtFlags & GTF_BLK_VOLATILE)
Expand Down
52 changes: 23 additions & 29 deletions src/jit/codegenarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -701,21 +701,17 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
// the xor ensures that only one of the two is setup, not both
assert((varNode != nullptr) ^ (addrNode != nullptr));

BYTE gcPtrArray[MAX_ARG_REG_COUNT] = {}; // TYPE_GC_NONE = 0
BYTE* gcPtrs = gcPtrArray;

unsigned gcPtrCount; // The count of GC pointers in the struct
int structSize;
bool isHfa;
StructTypeLayout* layout = nullptr;
int structSize;
bool isHfa;

// This is the varNum for our load operations,
// only used when we have a multireg struct with a LclVar source
unsigned varNumInp = BAD_VAR_NUM;

#ifdef _TARGET_ARM_
// On ARM32, size of reference map can be larger than MAX_ARG_REG_COUNT
gcPtrs = treeNode->gtGcPtrs;
gcPtrCount = treeNode->gtNumberReferenceSlots;
layout = treeNode->gtLayout;
#endif
// Setup the structSize, isHFa, and gcPtrCount
if (varNode != nullptr)
Expand All @@ -733,9 +729,7 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
// as that is how much stack is allocated for this LclVar
isHfa = varDsc->lvIsHfa();
#ifdef _TARGET_ARM64_
gcPtrCount = varDsc->lvStructGcCount;
for (unsigned i = 0; i < gcPtrCount; ++i)
gcPtrs[i] = varDsc->lvGcLayout[i];
layout = varDsc->lvLayout;
#endif // _TARGET_ARM_
}
else // addrNode is used
Expand All @@ -756,20 +750,20 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
}
#endif // _TARGET_ARM64_

CORINFO_CLASS_HANDLE objClass = source->gtObj.gtClass;
CORINFO_CLASS_HANDLE objClass = source->AsObj()->gtLayout->GetClass();

structSize = compiler->info.compCompHnd->getClassSize(objClass);
structSize = source->AsObj()->gtLayout->GetSize();
isHfa = compiler->IsHfa(objClass);
#ifdef _TARGET_ARM64_
gcPtrCount = compiler->info.compCompHnd->getClassGClayout(objClass, &gcPtrs[0]);
layout = source->AsObj()->gtLayout;
#endif
}

// If we have an HFA we can't have any GC pointers,
// if not then the max size for the the struct is 16 bytes
if (isHfa)
{
noway_assert(gcPtrCount == 0);
noway_assert(!layout->HasGCPtr());
}
#ifdef _TARGET_ARM64_
else
Expand All @@ -791,8 +785,8 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)

while (remainingSize >= 2 * TARGET_POINTER_SIZE)
{
var_types type0 = compiler->getJitGCType(gcPtrs[nextIndex + 0]);
var_types type1 = compiler->getJitGCType(gcPtrs[nextIndex + 1]);
var_types type0 = Compiler::getJitGCType(layout->GetGCPtr(nextIndex + 0));
var_types type1 = Compiler::getJitGCType(layout->GetGCPtr(nextIndex + 1));

if (varNode != nullptr)
{
Expand Down Expand Up @@ -827,7 +821,7 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
// str r2, [sp, #16]
while (remainingSize >= TARGET_POINTER_SIZE)
{
var_types type = compiler->getJitGCType(gcPtrs[nextIndex]);
var_types type = Compiler::getJitGCType(layout->GetGCPtr(nextIndex));

if (varNode != nullptr)
{
Expand Down Expand Up @@ -864,7 +858,7 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
{
if (remainingSize >= TARGET_POINTER_SIZE)
{
var_types nextType = compiler->getJitGCType(gcPtrs[nextIndex]);
var_types nextType = Compiler::getJitGCType(layout->GetGCPtr(nextIndex));
emitAttr nextAttr = emitTypeSize(nextType);
remainingSize -= TARGET_POINTER_SIZE;

Expand Down Expand Up @@ -897,7 +891,7 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
assert(varNode == nullptr);

// the left over size is smaller than a pointer and thus can never be a GC type
assert(varTypeIsGC(compiler->getJitGCType(gcPtrs[nextIndex])) == false);
assert(varTypeIsGC(Compiler::getJitGCType(layout->GetGCPtr(nextIndex))) == false);

var_types loadType = TYP_UINT;
if (loadSize == 1)
Expand Down Expand Up @@ -1071,9 +1065,9 @@ void CodeGen::genPutArgSplit(GenTreePutArgSplit* treeNode)
assert((varNode != nullptr) ^ (addrNode != nullptr));

// Setup the structSize, isHFa, and gcPtrCount
BYTE* gcPtrs = treeNode->gtGcPtrs;
unsigned gcPtrCount = treeNode->gtNumberReferenceSlots; // The count of GC pointers in the struct
int structSize = treeNode->getArgSize();
StructTypeLayout* layout = treeNode->gtLayout;
unsigned gcPtrCount = treeNode->gtNumberReferenceSlots; // The count of GC pointers in the struct
int structSize = treeNode->getArgSize();

// This is the varNum for our load operations,
// only used when we have a struct with a LclVar source
Expand Down Expand Up @@ -1109,7 +1103,7 @@ void CodeGen::genPutArgSplit(GenTreePutArgSplit* treeNode)
assert(baseReg != addrReg);

// We don't split HFA struct
assert(!compiler->IsHfa(source->gtObj.gtClass));
assert(!compiler->IsHfa(source->AsObj()->gtLayout->GetClass()));
}

// Put on stack first
Expand All @@ -1121,7 +1115,7 @@ void CodeGen::genPutArgSplit(GenTreePutArgSplit* treeNode)
assert(remainingSize % TARGET_POINTER_SIZE == 0);
while (remainingSize > 0)
{
var_types type = compiler->getJitGCType(gcPtrs[nextIndex]);
var_types type = Compiler::getJitGCType(layout->GetGCPtr(nextIndex));

if (varNode != nullptr)
{
Expand Down Expand Up @@ -2674,7 +2668,7 @@ void CodeGen::genJmpMethod(GenTree* jmp)
{
// Must be <= 16 bytes or else it wouldn't be passed in registers
noway_assert(EA_SIZE_IN_BYTES(varDsc->lvSize()) <= MAX_PASS_MULTIREG_BYTES);
loadType = compiler->getJitGCType(varDsc->lvGcLayout[0]);
loadType = Compiler::getJitGCType(varDsc->lvLayout->GetGCPtr(0));
}
else
{
Expand All @@ -2700,7 +2694,7 @@ void CodeGen::genJmpMethod(GenTree* jmp)
// Restore the second register.
argRegNext = genRegArgNext(argReg);

loadType = compiler->getJitGCType(varDsc->lvGcLayout[1]);
loadType = Compiler::getJitGCType(varDsc->lvLayout->GetGCPtr(1));
loadSize = emitActualTypeSize(loadType);
getEmitter()->emitIns_R_S(ins_Load(loadType), loadSize, argRegNext, varNum, TARGET_POINTER_SIZE);

Expand Down Expand Up @@ -2789,7 +2783,7 @@ void CodeGen::genJmpMethod(GenTree* jmp)
for (unsigned ofs = 0; ofs < maxSize; ofs += REGSIZE_BYTES)
{
unsigned idx = ofs / REGSIZE_BYTES;
loadType = compiler->getJitGCType(varDsc->lvGcLayout[idx]);
loadType = Compiler::getJitGCType(varDsc->lvLayout->GetGCPtr(idx));

if (varDsc->lvRegNum != argReg)
{
Expand Down Expand Up @@ -3394,7 +3388,7 @@ void CodeGen::genCodeForStoreBlk(GenTreeBlk* blkOp)

if (blkOp->OperIs(GT_STORE_OBJ) && blkOp->OperIsCopyBlkOp())
{
assert(blkOp->AsObj()->gtGcPtrCount != 0);
assert(blkOp->AsObj()->gtLayout->HasGCPtr());
genCodeForCpObj(blkOp->AsObj());
return;
}
Expand Down
25 changes: 15 additions & 10 deletions src/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1141,8 +1141,8 @@ unsigned CodeGenInterface::InferStructOpSizeAlign(GenTree* op, unsigned* alignme

if (op->gtOper == GT_OBJ)
{
CORINFO_CLASS_HANDLE clsHnd = op->AsObj()->gtClass;
opSize = compiler->info.compCompHnd->getClassSize(clsHnd);
CORINFO_CLASS_HANDLE clsHnd = op->AsObj()->gtLayout->GetClass();
opSize = op->AsObj()->gtLayout->GetSize();
alignment = roundUp(compiler->info.compCompHnd->getClassAlignmentRequirement(clsHnd), TARGET_POINTER_SIZE);
}
else if (op->gtOper == GT_LCL_VAR)
Expand Down Expand Up @@ -4704,8 +4704,7 @@ void CodeGen::genCheckUseBlockInit()
continue;
}

if (compiler->info.compInitMem || varTypeIsGC(varDsc->TypeGet()) || (varDsc->lvStructGcCount > 0) ||
varDsc->lvMustInit)
if (compiler->info.compInitMem || compiler->lvaTypeIsGC(varNum) || varDsc->lvMustInit)
{
if (varDsc->lvTracked)
{
Expand Down Expand Up @@ -4756,8 +4755,7 @@ void CodeGen::genCheckUseBlockInit()
#else // !FEATURE_SIMD
if ((!varDsc->lvTracked || (varDsc->lvType == TYP_STRUCT)) &&
#endif // !FEATURE_SIMD
varDsc->lvOnFrame &&
(!varDsc->lvIsTemp || varTypeIsGC(varDsc->TypeGet()) || (varDsc->lvStructGcCount > 0)))
varDsc->lvOnFrame && (!varDsc->lvIsTemp || compiler->lvaTypeIsGC(varNum)))
{
varDsc->lvMustInit = true;

Expand Down Expand Up @@ -4792,7 +4790,14 @@ void CodeGen::genCheckUseBlockInit()

if (varDsc->lvMustInit && varDsc->lvOnFrame)
{
initStkLclCnt += varDsc->lvStructGcCount;
if (varDsc->TypeGet() == TYP_STRUCT)
{
initStkLclCnt += varDsc->lvLayout->GetGCPtrCount();
}
else if (varTypeIsGC(varDsc->TypeGet()))
{
initStkLclCnt += 1;
}
}

if ((compiler->lvaLclSize(varNum) > (3 * TARGET_POINTER_SIZE)) && (largeGcStructs <= 4))
Expand Down Expand Up @@ -6244,12 +6249,12 @@ void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg,
(varDsc->lvExactSize >= TARGET_POINTER_SIZE))
{
// We only initialize the GC variables in the TYP_STRUCT
const unsigned slots = (unsigned)compiler->lvaLclSize(varNum) / REGSIZE_BYTES;
const BYTE* gcPtrs = compiler->lvaGetGcLayout(varNum);
StructTypeLayout* layout = varDsc->lvLayout;
const unsigned slots = layout->GetSlotCount();

for (unsigned i = 0; i < slots; i++)
{
if (gcPtrs[i] != TYPE_GC_NONE)
if (layout->GetGCPtr(i) != TYPE_GC_NONE)
{
getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE,
genGetZeroReg(initReg, pInitRegZeroed), varNum, i * REGSIZE_BYTES);
Expand Down
Loading

0 comments on commit 835f679

Please sign in to comment.