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

Commit

Permalink
StructPromote_0428
Browse files Browse the repository at this point in the history
Enable Struct promotion for 16-byte structs on Arm64
  • Loading branch information
briansull committed Apr 27, 2016
1 parent 597f60b commit b324afc
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 97 deletions.
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

0 comments on commit b324afc

Please sign in to comment.