{
sprintf_s(bufp, bufLength, "this in %s%c", compRegVarName(argReg), 0);
}
+#ifdef _TARGET_ARM_
+ else if (curArgTabEntry->isSplit)
+ {
+ regNumber firstReg = curArgTabEntry->regNum;
+ unsigned argNum = curArgTabEntry->argNum;
+ if (listCount == -1)
+ {
+ if (curArgTabEntry->numRegs == 1)
+ {
+ sprintf_s(bufp, bufLength, "arg%d %s out+%02x%c", argNum, compRegVarName(firstReg),
+ (curArgTabEntry->slotNum) * TARGET_POINTER_SIZE, 0);
+ }
+ else
+ {
+ regNumber lastReg = REG_STK;
+ char separator = (curArgTabEntry->numRegs == 2) ? ',' : '-';
+ if (curArgTabEntry->isHfaRegArg)
+ {
+ unsigned lastRegNum = genMapFloatRegNumToRegArgNum(firstReg) + curArgTabEntry->numRegs - 1;
+ lastReg = genMapFloatRegArgNumToRegNum(lastRegNum);
+ }
+ else
+ {
+ unsigned lastRegNum = genMapIntRegNumToRegArgNum(firstReg) + curArgTabEntry->numRegs - 1;
+ lastReg = genMapIntRegArgNumToRegNum(lastRegNum);
+ }
+ sprintf_s(bufp, bufLength, "arg%d %s%c%s out+%02x%c", argNum, compRegVarName(firstReg), separator,
+ compRegVarName(lastReg), (curArgTabEntry->slotNum) * TARGET_POINTER_SIZE, 0);
+ }
+ }
+ else
+ {
+ unsigned curArgNum = BAD_VAR_NUM;
+ bool isFloat = curArgTabEntry->isHfaRegArg;
+ if (isFloat)
+ {
+ curArgNum = genMapFloatRegNumToRegArgNum(firstReg) + listCount;
+ }
+ else
+ {
+ curArgNum = genMapIntRegNumToRegArgNum(firstReg) + listCount;
+ }
+
+ if (!isFloat && curArgNum < MAX_REG_ARG)
+ {
+ regNumber curReg = genMapIntRegArgNumToRegNum(curArgNum);
+ sprintf_s(bufp, bufLength, "arg%d m%d %s%c", argNum, listCount, compRegVarName(curReg), 0);
+ }
+ else if (isFloat && curArgNum < MAX_FLOAT_REG_ARG)
+ {
+ regNumber curReg = genMapFloatRegArgNumToRegNum(curArgNum);
+ sprintf_s(bufp, bufLength, "arg%d m%d %s%c", argNum, listCount, compRegVarName(curReg), 0);
+ }
+ else
+ {
+ unsigned stackSlot = listCount - curArgTabEntry->numRegs;
+ sprintf_s(bufp, bufLength, "arg%d m%d out+%s%c", argNum, listCount, stackSlot, 0);
+ }
+ }
+ return;
+ }
+#endif // _TARGET_ARM_
else
{
#if FEATURE_MULTIREG_ARGS
// Struct can be split into register(s) and stack on ARM
if (info->isSplit)
{
- if (arg->OperGet() != GT_OBJ)
+ assert(arg->OperGet() == GT_OBJ || arg->OperGet() == GT_FIELD_LIST);
+ // TODO: Need to check correctness for FastTailCall
+ if (call->IsFastTailCall())
{
- NYI_ARM("Lowering: Oper for struct argument is not GT_OBJ");
+ NYI_ARM("lower: struct argument by fast tail call");
}
putArg = new (comp, GT_PUTARG_SPLIT)
GenTreePutArgSplit(arg, info->slotNum PUT_STRUCT_ARG_STK_ONLY_ARG(info->numSlots), info->numRegs,
info->isHfaRegArg, call->IsFastTailCall(), call);
- // Set GC Pointer info
+ // If struct argument is morphed to GT_FIELD_LIST node(s),
+ // we can know GC info by type of each GT_FIELD_LIST node.
+ // So we skip setting GC Pointer info.
+ //
GenTreePutArgSplit* argSplit = putArg->AsPutArgSplit();
- BYTE* gcLayout = new (comp, CMK_Codegen) BYTE[info->numSlots + info->numRegs];
- unsigned numRefs = comp->info.compCompHnd->getClassGClayout(arg->gtObj.gtClass, gcLayout);
- argSplit->setGcPointers(numRefs, gcLayout);
+ if (arg->OperGet() == GT_OBJ)
+ {
+ BYTE* gcLayout = nullptr;
+ unsigned numRefs = 0;
+ GenTreeObj* argObj = arg->AsObj();
+
+ if (argObj->IsGCInfoInitialized())
+ {
+ gcLayout = argObj->gtGcPtrs;
+ numRefs = argObj->GetGcPtrCount();
+ }
+ else
+ {
+ // Set GC Pointer info
+ gcLayout = new (comp, CMK_Codegen) BYTE[info->numSlots + info->numRegs];
+ numRefs = comp->info.compCompHnd->getClassGClayout(arg->gtObj.gtClass, gcLayout);
+ argSplit->setGcPointers(numRefs, gcLayout);
+ }
- // Set type of registers
- for (unsigned index = 0; index < info->numRegs; index++)
+ // Set type of registers
+ for (unsigned index = 0; index < info->numRegs; index++)
+ {
+ var_types regType = comp->getJitGCType(gcLayout[index]);
+ argSplit->m_regType[index] = regType;
+ }
+ }
+ else
{
- var_types regType = comp->getJitGCType(gcLayout[index]);
- argSplit->m_regType[index] = regType;
+ GenTreeFieldList* fieldListPtr = arg->AsFieldList();
+ for (unsigned index = 0; index < info->numRegs; fieldListPtr = fieldListPtr->Rest(), index++)
+ {
+ var_types regType = fieldListPtr->TypeGet();
+ argSplit->m_regType[index] = regType;
+ }
}
}
else
}
argNode->gtLsraInfo.setDstCandidates(m_lsra, argMask);
+ if (putArgChild->OperGet() == GT_FIELD_LIST)
+ {
+ NYI_ARM("LSRA: Oper for split struct argument is GT_FIELD_LIST");
+ }
+
assert(putArgChild->TypeGet() == TYP_STRUCT);
assert(putArgChild->OperGet() == GT_OBJ);
// We could use a ldr/str sequence so we need a internal register
{
if (fgEntryPtr->isHfaRegArg)
{
- // We cannot handle split struct morphed to GT_FIELD_LIST yet
+ // We cannot handle HFA split struct morphed to GT_FIELD_LIST yet
NYI_ARM("Struct split between float registers and stack");
}
else if (fgEntryPtr->numSlots + fgEntryPtr->numRegs > 4)
{
return arg;
}
- else
- {
- // We cannot handle split struct morphed to GT_FIELD_LIST yet
- NYI_ARM("Struct split between integer registers and stack");
- }
}
else if (!fgEntryPtr->isHfaRegArg && fgEntryPtr->numSlots > 4)
{