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 Mar 23, 2019
1 parent d061cd2 commit 3688d39
Show file tree
Hide file tree
Showing 26 changed files with 932 additions and 741 deletions.
52 changes: 16 additions & 36 deletions src/jit/codegenarm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,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 @@ -721,29 +721,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 = layout->GetGCPtrType(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 @@ -753,30 +742,21 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
}
else
{
unsigned gcPtrCount = cpObjNode->gtGcPtrCount;

unsigned i = 0;
while (i < slots)
for (unsigned i = 0; i < slots; ++i)
{
switch (gcPtrs[i])
if (!layout->IsGCPtr(i))
{
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, EA_PTRSIZE, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
INS_FLAGS_DONT_CARE, INS_OPTS_LDST_POST_INC);
}
else
{
case TYPE_GC_NONE:
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);
emit->emitIns_R_R_I(INS_str, attr, 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--;
break;
// In the case of a GC-Pointer we'll call the ByRef write barrier helper
genEmitHelperCall(CORINFO_HELP_ASSIGN_BYREF, 0, EA_PTRSIZE);
}
++i;
}
assert(gcPtrCount == 0);
}

if (cpObjNode->gtFlags & GTF_BLK_VOLATILE)
Expand Down
67 changes: 29 additions & 38 deletions src/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2630,7 +2630,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 @@ -2639,7 +2639,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 @@ -2666,7 +2666,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 @@ -2675,8 +2675,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(layout->GetGCPtrType(i + 0));
emitAttr attr1 = emitTypeSize(layout->GetGCPtrType(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 @@ -2688,7 +2688,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(layout->GetGCPtrType(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 @@ -2698,42 +2698,33 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
}
else
{
unsigned gcPtrCount = cpObjNode->gtGcPtrCount;

unsigned i = 0;
while (i < slots)
for (unsigned i = 0; i < slots; ++i)
{
switch (gcPtrs[i])
if (!layout->IsGCPtr(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))
{
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);
emit->emitIns_R_R_R_I(INS_stp, EA_8BYTE, tmpReg, tmpReg2, REG_WRITE_BARRIER_DST_BYREF,
2 * TARGET_POINTER_SIZE, INS_OPTS_POST_INDEX);
++i; // extra increment of i, since we are copying two items
}
else
{
emit->emitIns_R_R_I(INS_ldr, EA_8BYTE, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
INS_OPTS_POST_INDEX);
emit->emitIns_R_R_I(INS_str, EA_8BYTE, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
INS_OPTS_POST_INDEX);
}
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--;
break;
// Check if the next slot's type is also TYP_GC_NONE and use ldp/stp
if ((i + 1 < slots) && !layout->IsGCPtr(i + 1))
{
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);
emit->emitIns_R_R_R_I(INS_stp, EA_8BYTE, tmpReg, tmpReg2, REG_WRITE_BARRIER_DST_BYREF,
2 * TARGET_POINTER_SIZE, INS_OPTS_POST_INDEX);
++i; // extra increment of i, since we are copying two items
}
else
{
emit->emitIns_R_R_I(INS_ldr, EA_8BYTE, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
INS_OPTS_POST_INDEX);
emit->emitIns_R_R_I(INS_str, EA_8BYTE, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
INS_OPTS_POST_INDEX);
}
}
else
{
// In the case of a GC-Pointer we'll call the ByRef write barrier helper
genEmitHelperCall(CORINFO_HELP_ASSIGN_BYREF, 0, EA_PTRSIZE);
}
++i;
}
assert(gcPtrCount == 0);
}

if (cpObjNode->gtFlags & GTF_BLK_VOLATILE)
Expand Down
71 changes: 30 additions & 41 deletions src/jit/codegenarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -710,22 +710,14 @@ 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;
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;
#endif
// Setup the structSize, isHFa, and gcPtrCount
if (varNode != nullptr)
{
Expand All @@ -738,14 +730,17 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
assert(varDsc->lvType == TYP_STRUCT);
assert(varDsc->lvOnFrame && !varDsc->lvRegister);

structSize = varDsc->lvSize(); // This yields the roundUp size, but that is fine
// as that is how much stack is allocated for this LclVar
// This yields the roundUp size, but that is fine
// as that is how much stack is allocated for this LclVar
structSize = varDsc->lvSize();

isHfa = varDsc->lvIsHfa();
#ifdef _TARGET_ARM64_
gcPtrCount = varDsc->lvStructGcCount;
for (unsigned i = 0; i < gcPtrCount; ++i)
gcPtrs[i] = varDsc->lvGcLayout[i];
#endif // _TARGET_ARM_

#ifdef _TARGET_ARM_
layout = treeNode->gtLayout;
#else // _TARGET_ARM64_
layout = varDsc->lvLayout;
#endif // _TARGET_ARM64_
}
else // addrNode is used
{
Expand All @@ -765,20 +760,16 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
}
#endif // _TARGET_ARM64_

CORINFO_CLASS_HANDLE objClass = source->gtObj.gtClass;

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

// 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 @@ -800,8 +791,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 = layout->GetGCPtrType(nextIndex + 0);
var_types type1 = layout->GetGCPtrType(nextIndex + 1);

if (varNode != nullptr)
{
Expand Down Expand Up @@ -836,7 +827,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 = layout->GetGCPtrType(nextIndex);

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

Expand Down Expand Up @@ -906,7 +897,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(!layout->IsGCPtr(nextIndex));

var_types loadType = TYP_UINT;
if (loadSize == 1)
Expand Down Expand Up @@ -1079,10 +1070,8 @@ void CodeGen::genPutArgSplit(GenTreePutArgSplit* treeNode)
// the xor ensures that only one of the two is setup, not both
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;
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 @@ -1118,7 +1107,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 @@ -1130,7 +1119,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 = layout->GetGCPtrType(nextIndex);

if (varNode != nullptr)
{
Expand Down Expand Up @@ -2679,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 = varDsc->lvLayout->GetGCPtrType(0);
}
else
{
Expand All @@ -2705,7 +2694,7 @@ void CodeGen::genJmpMethod(GenTree* jmp)
// Restore the second register.
argRegNext = genRegArgNext(argReg);

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

Expand Down Expand Up @@ -2796,7 +2785,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 = varDsc->lvLayout->GetGCPtrType(idx);

if (varDsc->lvRegNum != argReg)
{
Expand Down Expand Up @@ -3267,7 +3256,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
Loading

0 comments on commit 3688d39

Please sign in to comment.