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

ARM64: Enable Struct Promotion for most Mutireg structs #4632

Merged
merged 2 commits into from
Apr 28, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 39 additions & 6 deletions src/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6445,6 +6445,7 @@ CodeGen::genIntrinsic(GenTreePtr treeNode)
//
void CodeGen::genPutArgStk(GenTreePtr treeNode)
{
assert(treeNode->OperGet() == GT_PUTARG_STK);
var_types targetType = treeNode->TypeGet();
emitter *emit = getEmitter();

Expand Down Expand Up @@ -6493,8 +6494,9 @@ void CodeGen::genPutArgStk(GenTreePtr treeNode)
{
varNum = compiler->lvaOutgoingArgSpaceVar;
}
bool isStruct = (targetType == TYP_STRUCT) || (data->OperGet() == GT_LIST);

if (targetType != TYP_STRUCT) // a normal non-Struct argument
if (!isStruct) // a normal non-Struct argument
{
instruction storeIns = ins_Store(targetType);
emitAttr storeAttr = emitTypeSize(targetType);
Expand All @@ -6512,20 +6514,22 @@ void CodeGen::genPutArgStk(GenTreePtr treeNode)
emit->emitIns_S_R(storeIns, storeAttr, data->gtRegNum, varNum, argOffset);
}
}
else // We have a TYP_STRUCT argument (it also must be a 16-byte multi-reg struct)
else // We have a TYP_STRUCT argument (it currently must be a 16-byte multi-reg struct)
{
// We will use two store instructions that each write a register sized value

// We must have a multi-reg struct that takes two slots
assert(curArgTabEntry->numSlots == 2);
assert(data->isContained()); // We expect that this node was marked as contained in LowerArm64

// In lowerArm64 we reserved two internal integer registers for this 16-byte TYP_STRUCT
regNumber loReg = REG_NA;
regNumber hiReg = REG_NA;
genGetRegPairFromMask(treeNode->gtRsvdRegs, &loReg, &hiReg);
assert(loReg != REG_NA);
assert(hiReg != REG_NA);

if (data->OperGet() != GT_LIST)
{
// In lowerArm64 we reserved two internal integer registers for this 16-byte TYP_STRUCT
genGetRegPairFromMask(treeNode->gtRsvdRegs, &loReg, &hiReg);
}

// We will need to record the GC type used by each of the load instructions
// so that we use the same type in each of the store instructions
Expand Down Expand Up @@ -6697,6 +6701,31 @@ void CodeGen::genPutArgStk(GenTreePtr treeNode)
}
}
}
else if (data->OperGet() == GT_LIST)
{
// Deal with multi register passed struct args.
GenTreeArgList* argListPtr = data->AsArgList();
unsigned iterationNum = 0;
for (; argListPtr != nullptr; argListPtr = argListPtr->Rest(), iterationNum++)
{
GenTreePtr nextArgNode = argListPtr->gtOp.gtOp1;
genConsumeReg(nextArgNode);

if (iterationNum == 0)
{
// record loReg and type0 for the store to the out arg space
loReg = nextArgNode->gtRegNum;
type0 = nextArgNode->TypeGet();
}
else
{
assert(iterationNum == 1);
// record hiReg and type1 for the store to the out arg space
hiReg = nextArgNode->gtRegNum;;
type1 = nextArgNode->TypeGet();
}
}
}

if ((data->OperGet() == GT_LCL_VAR) || (data->OperGet() == GT_LCL_VAR_ADDR))
{
Expand All @@ -6719,6 +6748,10 @@ void CodeGen::genPutArgStk(GenTreePtr treeNode)
emit->emitIns_R_S(ins_Load(type1), emitTypeSize(type1), hiReg, varNum, TARGET_POINTER_SIZE);
}

// We are required to set these two values above
assert(loReg != REG_NA);
assert(hiReg != REG_NA);

// We are required to set these two values above, so that the stores have the same GC type as the loads
assert(type0 != TYP_UNKNOWN);
assert(type1 != TYP_UNKNOWN);
Expand Down
3 changes: 2 additions & 1 deletion src/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -2031,6 +2031,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void gtGetArgMsg (GenTreePtr call,
GenTreePtr arg,
unsigned argNum,
int listCount,
char* bufp,
unsigned bufLength);
void gtGetLateArgMsg (GenTreePtr call,
Expand Down Expand Up @@ -8817,7 +8818,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)

void fgMorphMultiregStructArgs(GenTreeCall* call);
GenTreePtr fgMorphMultiregStructArg (GenTreePtr arg);
GenTreePtr fgMorphMultiregStructArg (GenTreePtr arg, fgArgTabEntryPtr fgEntryPtr);

}; // end of class Compiler

Expand Down
29 changes: 22 additions & 7 deletions src/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8717,6 +8717,8 @@ void Compiler::gtDispTree(GenTreePtr tree,
// call - The call for which 'arg' is an argument
// arg - The argument for which a message should be constructed
// argNum - The ordinal number of the arg in the argument list
// listCount - When printing in Linear form this is the count for a multireg GT_LIST
// or -1 if we are not printing in Linear form
// bufp - A pointer to the buffer into which the message is written
// bufLength - The length of the buffer pointed to by bufp
//
Expand All @@ -8730,14 +8732,14 @@ void Compiler::gtDispTree(GenTreePtr tree,
void Compiler::gtGetArgMsg(GenTreePtr call,
GenTreePtr arg,
unsigned argNum,
int listCount,
char* bufp,
unsigned bufLength)
{
if (call->gtCall.gtCallLateArgs != NULL)
{
fgArgTabEntryPtr curArgTabEntry = gtArgEntryByNode(call, arg);
fgArgTabEntryPtr curArgTabEntry = gtArgEntryByArgNum(call, argNum);
assert(curArgTabEntry);
assert(curArgTabEntry->argNum == argNum);

if (arg->gtFlags & GTF_LATE_ARG)
{
Expand All @@ -8746,7 +8748,19 @@ void Compiler::gtGetArgMsg(GenTreePtr call,
else
{
#if FEATURE_FIXED_OUT_ARGS
sprintf_s(bufp, bufLength, "arg%d in out+%02x%c", argNum, curArgTabEntry->slotNum * TARGET_POINTER_SIZE, 0);
if (listCount == -1)
{
sprintf_s(bufp, bufLength, "arg%d out+%02x%c", argNum, curArgTabEntry->slotNum * TARGET_POINTER_SIZE, 0);
}
else if (listCount == 1)
{
sprintf_s(bufp, bufLength, "arg%d hi +%02x%c", argNum, (curArgTabEntry->slotNum + 1) * TARGET_POINTER_SIZE, 0);
}
else
{
assert(listCount == 0);
sprintf_s(bufp, bufLength, "arg%d lo +%02x%c", argNum, (curArgTabEntry->slotNum + 0) * TARGET_POINTER_SIZE, 0);
}
#else
sprintf_s(bufp, bufLength, "arg%d on STK%c", argNum, 0);
#endif
Expand Down Expand Up @@ -8869,7 +8883,7 @@ void Compiler::gtDispArgList(GenTreePtr tree,
GenTree* arg = args->gtOp.gtOp1;
if (!arg->IsNothingNode() && !arg->IsArgPlaceHolderNode())
{
gtGetArgMsg(tree, arg, argnum, bufp, BufLength);
gtGetArgMsg(tree, arg, argnum, -1, bufp, BufLength);
if (argListIsLastChild && (args->gtOp.gtOp2 == nullptr))
{
arcType = IIArcBottom;
Expand Down Expand Up @@ -9105,13 +9119,14 @@ GenTreePtr Compiler::gtDispLinearTree(GenTreeStmt* curStmt,
indentStack->Push(indentInfo);
if (child == tree->gtCall.gtCallArgs)
{
gtGetArgMsg(tree, listNested, listElemNum, bufp, BufLength);
gtGetArgMsg(tree, listNested, listElemNum, listCount, bufp, BufLength);
}
else
{
assert(child == tree->gtCall.gtCallLateArgs);
gtGetLateArgMsg(tree, listNested, listElemNum, listCount++, bufp, BufLength);
gtGetLateArgMsg(tree, listNested, listElemNum, listCount, bufp, BufLength);
}
listCount++;
nextLinearNode = gtDispLinearTree(curStmt, nextLinearNode, listElemNested, indentStack, bufp);
indentStack->Pop();
}
Expand All @@ -9129,7 +9144,7 @@ GenTreePtr Compiler::gtDispLinearTree(GenTreeStmt* curStmt,

if (child == tree->gtCall.gtCallArgs)
{
gtGetArgMsg(tree, listElem, listElemNum, bufp, BufLength);
gtGetArgMsg(tree, listElem, listElemNum, -1, bufp, BufLength);
}
else
{
Expand Down
51 changes: 32 additions & 19 deletions src/jit/lowerarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ void Lowering::TreeNodeInfoInit(GenTree* stmt)

// To avoid redundant moves, request that the argument child tree be
// computed in the register in which the argument is passed to the call.
putArgChild ->gtLsraInfo.setSrcCandidates(l, targetMask);
putArgChild->gtLsraInfo.setSrcCandidates(l, targetMask);

// We consume one source for each item in this list
info->srcCount++;
Expand Down Expand Up @@ -694,7 +694,7 @@ void Lowering::TreeNodeInfoInit(GenTree* stmt)
{
GenTreePtr arg = args->gtOp.gtOp1;

// Skip arguments that havew been moved to the Late Arg list
// Skip arguments that have been moved to the Late Arg list
if (!(args->gtFlags & GTF_LATE_ARG))
{
if (arg->gtOper == GT_PUTARG_STK)
Expand Down Expand Up @@ -1040,33 +1040,46 @@ void Lowering::TreeNodeInfoInitPutArgStk(GenTree* argNode, fgArgTabEntryPtr info
argNode->gtLsraInfo.srcCount = 1;
argNode->gtLsraInfo.dstCount = 0;

// Do we have a TYP_STRUCT argument, if so it must be a 16-byte pass-by-value struct
if (putArgChild->TypeGet() == TYP_STRUCT)
// Do we have a TYP_STRUCT argument (or a GT_LIST), if so it must be a 16-byte pass-by-value struct
if ((putArgChild->TypeGet() == TYP_STRUCT) || (putArgChild->OperGet() == GT_LIST))
{
// We will use two store instructions that each write a register sized value

// We must have a multi-reg struct
assert(info->numSlots >= 2);

// We can use a ldp/stp sequence so we need two internal registers
argNode->gtLsraInfo.internalIntCount = 2;

if (putArgChild->OperGet() == GT_OBJ)
if (putArgChild->OperGet() == GT_LIST)
{
// We consume all of the items in the GT_LIST
argNode->gtLsraInfo.srcCount = info->numSlots;
}
else
{
GenTreePtr objChild = putArgChild->gtOp.gtOp1;
if (objChild->OperGet() == GT_LCL_VAR_ADDR)
// We could use a ldp/stp sequence so we need two internal registers
argNode->gtLsraInfo.internalIntCount = 2;

if (putArgChild->OperGet() == GT_OBJ)
{
// We will generate all of the code for the GT_PUTARG_STK, the GT_OBJ and the GT_LCL_VAR_ADDR
// as one contained operation
//
MakeSrcContained(putArgChild, objChild);
GenTreePtr objChild = putArgChild->gtOp.gtOp1;
if (objChild->OperGet() == GT_LCL_VAR_ADDR)
{
// We will generate all of the code for the GT_PUTARG_STK, the GT_OBJ and the GT_LCL_VAR_ADDR
// as one contained operation
//
MakeSrcContained(putArgChild, objChild);
}
}
}

// We will generate all of the code for the GT_PUTARG_STK and it's child node
// as one contained operation
//
MakeSrcContained(argNode, putArgChild);
// We will generate all of the code for the GT_PUTARG_STK and it's child node
// as one contained operation
//
MakeSrcContained(argNode, putArgChild);
}
}
else
{
// We must not have a multi-reg struct
assert(info->numSlots == 1);
}
}

Expand Down
Loading