summaryrefslogtreecommitdiff
path: root/src/jit/lowerarm64.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/lowerarm64.cpp')
-rw-r--r--src/jit/lowerarm64.cpp149
1 files changed, 79 insertions, 70 deletions
diff --git a/src/jit/lowerarm64.cpp b/src/jit/lowerarm64.cpp
index 1720c62acb..cc9e2266d2 100644
--- a/src/jit/lowerarm64.cpp
+++ b/src/jit/lowerarm64.cpp
@@ -126,6 +126,10 @@ void Lowering::TreeNodeInfoInit(GenTree* tree)
TreeNodeInfo* info = &(tree->gtLsraInfo);
RegisterType registerType = TypeGet(tree);
+ JITDUMP("TreeNodeInfoInit for: ");
+ DISPNODE(tree);
+ JITDUMP("\n");
+
switch (tree->OperGet())
{
GenTree* op1;
@@ -202,6 +206,7 @@ void Lowering::TreeNodeInfoInit(GenTree* tree)
__fallthrough;
case GT_LIST:
+ case GT_FIELD_LIST:
case GT_ARGPLACE:
case GT_NO_OP:
case GT_START_NONGC:
@@ -485,7 +490,7 @@ void Lowering::TreeNodeInfoInit(GenTree* tree)
case GT_LE:
case GT_GE:
case GT_GT:
- LowerCmp(tree);
+ TreeNodeInfoInitCmp(tree);
break;
case GT_CKFINITE:
@@ -524,12 +529,12 @@ void Lowering::TreeNodeInfoInit(GenTree* tree)
break;
case GT_BLK:
- case GT_OBJ:
case GT_DYN_BLK:
// These should all be eliminated prior to Lowering.
assert(!"Non-store block node in Lowering");
info->srcCount = 0;
info->dstCount = 0;
+ break;
case GT_STORE_BLK:
case GT_STORE_OBJ:
@@ -537,6 +542,12 @@ void Lowering::TreeNodeInfoInit(GenTree* tree)
TreeNodeInfoInitBlockStore(tree->AsBlk());
break;
+ case GT_INIT_VAL:
+ // Always a passthrough of its child's value.
+ info->srcCount = 0;
+ info->dstCount = 0;
+ break;
+
case GT_LCLHEAP:
{
info->srcCount = 1;
@@ -977,7 +988,7 @@ void Lowering::TreeNodeInfoInitCall(GenTreeCall* call)
for (GenTreePtr list = call->gtCallLateArgs; list; list = list->MoveNext())
{
- assert(list->IsList());
+ assert(list->OperIsList());
GenTreePtr argNode = list->Current();
@@ -989,7 +1000,7 @@ void Lowering::TreeNodeInfoInitCall(GenTreeCall* call)
// late arg that is not passed in a register
assert(argNode->gtOper == GT_PUTARG_STK);
- TreeNodeInfoInitPutArgStk(argNode, curArgTabEntry);
+ TreeNodeInfoInitPutArgStk(argNode->AsPutArgStk(), curArgTabEntry);
continue;
}
@@ -1003,16 +1014,16 @@ void Lowering::TreeNodeInfoInitCall(GenTreeCall* call)
argNode = argNode->gtEffectiveVal();
- // A GT_LIST has a TYP_VOID, but is used to represent a multireg struct
- if (varTypeIsStruct(argNode) || (argNode->gtOper == GT_LIST))
+ // A GT_FIELD_LIST has a TYP_VOID, but is used to represent a multireg struct
+ if (varTypeIsStruct(argNode) || (argNode->gtOper == GT_FIELD_LIST))
{
GenTreePtr actualArgNode = argNode;
unsigned originalSize = 0;
- if (argNode->gtOper == GT_LIST)
+ if (argNode->gtOper == GT_FIELD_LIST)
{
// There could be up to 2-4 PUTARG_REGs in the list (3 or 4 can only occur for HFAs)
- GenTreeArgList* argListPtr = argNode->AsArgList();
+ GenTreeFieldList* fieldListPtr = argNode->AsFieldList();
// Initailize the first register and the first regmask in our list
regNumber targetReg = argReg;
@@ -1020,9 +1031,9 @@ void Lowering::TreeNodeInfoInitCall(GenTreeCall* call)
unsigned iterationNum = 0;
originalSize = 0;
- for (; argListPtr; argListPtr = argListPtr->Rest())
+ for (; fieldListPtr; fieldListPtr = fieldListPtr->Rest())
{
- GenTreePtr putArgRegNode = argListPtr->gtOp.gtOp1;
+ GenTreePtr putArgRegNode = fieldListPtr->Current();
assert(putArgRegNode->gtOper == GT_PUTARG_REG);
GenTreePtr putArgChild = putArgRegNode->gtOp.gtOp1;
@@ -1115,7 +1126,7 @@ void Lowering::TreeNodeInfoInitCall(GenTreeCall* call)
assert(curArgTabEntry->regNum == REG_STK);
- TreeNodeInfoInitPutArgStk(arg, curArgTabEntry);
+ TreeNodeInfoInitPutArgStk(arg->AsPutArgStk(), curArgTabEntry);
}
else
{
@@ -1154,7 +1165,7 @@ void Lowering::TreeNodeInfoInitCall(GenTreeCall* call)
// Notes:
// Set the child node(s) to be contained when we have a multireg arg
//
-void Lowering::TreeNodeInfoInitPutArgStk(GenTree* argNode, fgArgTabEntryPtr info)
+void Lowering::TreeNodeInfoInitPutArgStk(GenTreePutArgStk* argNode, fgArgTabEntryPtr info)
{
assert(argNode->gtOper == GT_PUTARG_STK);
@@ -1166,14 +1177,14 @@ void Lowering::TreeNodeInfoInitPutArgStk(GenTree* argNode, fgArgTabEntryPtr info
argNode->gtLsraInfo.srcCount = 1;
argNode->gtLsraInfo.dstCount = 0;
- // Do we have a TYP_STRUCT argument (or a GT_LIST), if so it must be a multireg pass-by-value struct
- if ((putArgChild->TypeGet() == TYP_STRUCT) || (putArgChild->OperGet() == GT_LIST))
+ // Do we have a TYP_STRUCT argument (or a GT_FIELD_LIST), if so it must be a multireg pass-by-value struct
+ if ((putArgChild->TypeGet() == TYP_STRUCT) || (putArgChild->OperGet() == GT_FIELD_LIST))
{
// We will use store instructions that each write a register sized value
- if (putArgChild->OperGet() == GT_LIST)
+ if (putArgChild->OperGet() == GT_FIELD_LIST)
{
- // We consume all of the items in the GT_LIST
+ // We consume all of the items in the GT_FIELD_LIST
argNode->gtLsraInfo.srcCount = info->numSlots;
}
else
@@ -1219,8 +1230,9 @@ void Lowering::TreeNodeInfoInitPutArgStk(GenTree* argNode, fgArgTabEntryPtr info
void Lowering::TreeNodeInfoInitBlockStore(GenTreeBlk* blkNode)
{
- GenTree* dstAddr = blkNode->Addr();
- unsigned size;
+ GenTree* dstAddr = blkNode->Addr();
+ unsigned size = blkNode->gtBlkSize;
+ GenTree* source = blkNode->Data();
LinearScan* l = m_lsra;
Compiler* compiler = comp;
@@ -1228,16 +1240,44 @@ void Lowering::TreeNodeInfoInitBlockStore(GenTreeBlk* blkNode)
// We may require an additional source or temp register for the size.
blkNode->gtLsraInfo.srcCount = 2;
blkNode->gtLsraInfo.dstCount = 0;
+ GenTreePtr srcAddrOrFill = nullptr;
+ bool isInitBlk = blkNode->OperIsInitBlkOp();
- if ((blkNode->OperGet() == GT_STORE_OBJ) && (blkNode->AsObj()->gtGcPtrCount == 0))
+ if (!isInitBlk)
{
- blkNode->SetOper(GT_STORE_BLK);
+ // CopyObj or CopyBlk
+ if ((blkNode->OperGet() == GT_STORE_OBJ) && ((blkNode->AsObj()->gtGcPtrCount == 0) || blkNode->gtBlkOpGcUnsafe))
+ {
+ blkNode->SetOper(GT_STORE_BLK);
+ }
+ if (source->gtOper == GT_IND)
+ {
+ srcAddrOrFill = blkNode->Data()->gtGetOp1();
+ // We're effectively setting source as contained, but can't call MakeSrcContained, because the
+ // "inheritance" of the srcCount is to a child not a parent - it would "just work" but could be misleading.
+ // If srcAddr is already non-contained, we don't need to change it.
+ if (srcAddrOrFill->gtLsraInfo.getDstCount() == 0)
+ {
+ srcAddrOrFill->gtLsraInfo.setDstCount(1);
+ srcAddrOrFill->gtLsraInfo.setSrcCount(source->gtLsraInfo.srcCount);
+ }
+ m_lsra->clearOperandCounts(source);
+ }
+ else if (!source->IsMultiRegCall() && !source->OperIsSIMD())
+ {
+ assert(source->IsLocal());
+ MakeSrcContained(blkNode, source);
+ }
}
- if (blkNode->OperIsInitBlkOp())
+ if (isInitBlk)
{
- unsigned size = blkNode->gtBlkSize;
- GenTreePtr initVal = blkNode->Data();
+ GenTreePtr initVal = source;
+ if (initVal->OperIsInitVal())
+ {
+ initVal = initVal->gtGetOp1();
+ }
+ srcAddrOrFill = initVal;
#if 0
// TODO-ARM64-CQ: Currently we generate a helper call for every
@@ -1264,8 +1304,6 @@ void Lowering::TreeNodeInfoInitBlockStore(GenTreeBlk* blkNode)
initVal->gtType = TYP_LONG;
}
- MakeSrcContained(tree, blockSize);
-
// In case we have a buffer >= 16 bytes
// we can use SSE2 to do a 128-bit store in a single
// instruction.
@@ -1282,7 +1320,7 @@ void Lowering::TreeNodeInfoInitBlockStore(GenTreeBlk* blkNode)
else
#endif // 0
{
- // The helper follows the regular AMD64 ABI.
+ // The helper follows the regular ABI.
dstAddr->gtLsraInfo.setSrcCandidates(l, RBM_ARG_0);
initVal->gtLsraInfo.setSrcCandidates(l, RBM_ARG_1);
blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindHelper;
@@ -1306,34 +1344,12 @@ void Lowering::TreeNodeInfoInitBlockStore(GenTreeBlk* blkNode)
{
// CopyObj or CopyBlk
// Sources are src and dest and size if not constant.
- unsigned size = blkNode->gtBlkSize;
- GenTreePtr source = blkNode->Data();
- GenTree* srcAddr = nullptr;
- if (source->gtOper == GT_IND)
- {
- srcAddr = blkNode->Data()->gtGetOp1();
- // We're effectively setting source as contained, but can't call MakeSrcContained, because the
- // "inheritance" of the srcCount is to a child not a parent - it would "just work" but could be misleading.
- // If srcAddr is already non-contained, we don't need to change it.
- if (srcAddr->gtLsraInfo.getDstCount() == 0)
- {
- srcAddr->gtLsraInfo.setDstCount(1);
- srcAddr->gtLsraInfo.setSrcCount(source->gtLsraInfo.srcCount);
- }
- m_lsra->clearOperandCounts(source);
- }
- else
- {
- assert(source->IsLocal());
- MakeSrcContained(blkNode, source);
- }
if (blkNode->OperGet() == GT_STORE_OBJ)
{
// CopyObj
GenTreeObj* objNode = blkNode->AsObj();
- GenTreePtr source = objNode->Data();
unsigned slots = objNode->gtSlots;
@@ -1362,16 +1378,19 @@ void Lowering::TreeNodeInfoInitBlockStore(GenTreeBlk* blkNode)
blkNode->gtLsraInfo.internalIntCount = 1;
dstAddr->gtLsraInfo.setSrcCandidates(l, RBM_WRITE_BARRIER_DST_BYREF);
- srcAddr->gtLsraInfo.setSrcCandidates(l, RBM_WRITE_BARRIER_SRC_BYREF);
+ // If we have a source address we want it in REG_WRITE_BARRIER_SRC_BYREF.
+ // Otherwise, if it is a local, codegen will put its address in REG_WRITE_BARRIER_SRC_BYREF,
+ // which is killed by a StoreObj (and thus needn't be reserved).
+ if (srcAddrOrFill != nullptr)
+ {
+ srcAddrOrFill->gtLsraInfo.setSrcCandidates(l, RBM_WRITE_BARRIER_SRC_BYREF);
+ }
}
else
{
// CopyBlk
- unsigned size = blkNode->gtBlkSize;
- GenTreePtr dstAddr = blkNode->Addr();
- GenTreePtr srcAddr = blkNode->Data();
- short internalIntCount = 0;
- regMaskTP internalIntCandidates = RBM_NONE;
+ short internalIntCount = 0;
+ regMaskTP internalIntCandidates = RBM_NONE;
#if 0
// In case of a CpBlk with a constant size and less than CPBLK_UNROLL_LIMIT size
@@ -1379,11 +1398,8 @@ void Lowering::TreeNodeInfoInitBlockStore(GenTreeBlk* blkNode)
// TODO-ARM64-CQ: cpblk loop unrolling is currently not implemented.
- if (blockSize->IsCnsIntOrI() && blockSize->gtIntCon.gtIconVal <= CPBLK_UNROLL_LIMIT)
+ if ((size != 0) && (size <= INITBLK_UNROLL_LIMIT))
{
- assert(!blockSize->IsIconHandle());
- ssize_t size = blockSize->gtIntCon.gtIconVal;
-
// If we have a buffer between XMM_REGSIZE_BYTES and CPBLK_UNROLL_LIMIT bytes, we'll use SSE2.
// Structs and buffer with sizes <= CPBLK_UNROLL_LIMIT bytes are occurring in more than 95% of
// our framework assemblies, so this is the main code generation scheme we'll use.
@@ -1404,9 +1420,9 @@ void Lowering::TreeNodeInfoInitBlockStore(GenTreeBlk* blkNode)
// If src or dst are on stack, we don't have to generate the address into a register
// because it's just some constant+SP
- if (srcAddr->OperIsLocalAddr())
+ if (srcAddr != nullptr && srcAddrOrFill->OperIsLocalAddr())
{
- MakeSrcContained(blkNode, srcAddr);
+ MakeSrcContained(blkNode, srcAddrOrFill);
}
if (dstAddr->OperIsLocalAddr())
@@ -1425,15 +1441,9 @@ void Lowering::TreeNodeInfoInitBlockStore(GenTreeBlk* blkNode)
dstAddr->gtLsraInfo.setSrcCandidates(l, RBM_ARG_0);
// The srcAddr goes in arg1.
- if (srcAddr != nullptr)
+ if (srcAddrOrFill != nullptr)
{
- srcAddr->gtLsraInfo.setSrcCandidates(l, RBM_ARG_1);
- }
- else
- {
- // This is a local; we'll use a temp register for its address.
- internalIntCandidates |= RBM_ARG_1;
- internalIntCount++;
+ srcAddrOrFill->gtLsraInfo.setSrcCandidates(l, RBM_ARG_1);
}
if (size != 0)
{
@@ -1447,7 +1457,6 @@ void Lowering::TreeNodeInfoInitBlockStore(GenTreeBlk* blkNode)
noway_assert(blkNode->gtOper == GT_STORE_DYN_BLK);
blkNode->gtLsraInfo.setSrcCount(3);
GenTree* blockSize = blkNode->AsDynBlk()->gtDynamicSize;
- assert(!blockSize->IsIconHandle());
blockSize->gtLsraInfo.setSrcCandidates(l, RBM_ARG_2);
}
blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindHelper;
@@ -1860,7 +1869,7 @@ void Lowering::SetIndirAddrOpCounts(GenTreePtr indirTree)
}
}
-void Lowering::LowerCmp(GenTreePtr tree)
+void Lowering::TreeNodeInfoInitCmp(GenTreePtr tree)
{
TreeNodeInfo* info = &(tree->gtLsraInfo);