diff options
Diffstat (limited to 'src/jit/lowerarm64.cpp')
-rw-r--r-- | src/jit/lowerarm64.cpp | 149 |
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); |