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

Commit 780400f

Browse files
committed
Decomposing 64-bit storeind instruction to 32-bit storeind instructions
1 parent f6cd99c commit 780400f

File tree

2 files changed

+314
-9
lines changed

2 files changed

+314
-9
lines changed

src/jit/lower.cpp

Lines changed: 307 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ void Lowering::DecomposeNode(GenTreePtr* pTree, Compiler::fgWalkData* data)
308308
comp->lvaIncRefCnts(tree);
309309
comp->lvaIncRefCnts(hiStore);
310310

311+
tree->gtNext = hiRhs;
311312
hiRhs->gtPrev = tree;
312313
hiRhs->gtNext = hiStore;
313314
hiStore->gtPrev = hiRhs;
@@ -318,7 +319,9 @@ void Lowering::DecomposeNode(GenTreePtr* pTree, Compiler::fgWalkData* data)
318319
}
319320
nextTree = hiRhs;
320321
GenTreeStmt* stmt;
321-
if (comp->compCurStmt->gtStmt.gtStmtExpr == tree)
322+
GenTreeStmt* currStmt = comp->compCurStmt->AsStmt();
323+
bool isEmbeddedStmt = !currStmt->gtStmtIsTopLevel();
324+
if (!isEmbeddedStmt)
322325
{
323326
tree->gtNext = nullptr;
324327
hiRhs->gtPrev = nullptr;
@@ -327,7 +330,13 @@ void Lowering::DecomposeNode(GenTreePtr* pTree, Compiler::fgWalkData* data)
327330
}
328331
else
329332
{
330-
stmt = comp->fgMakeEmbeddedStmt(comp->compCurBB, hiStore, comp->compCurStmt);
333+
GenTree* parentStmt = currStmt;
334+
while ((parentStmt != nullptr) && (!parentStmt->AsStmt()->gtStmtIsTopLevel()))
335+
{
336+
parentStmt = parentStmt->gtPrev;
337+
}
338+
assert(parentStmt);
339+
stmt = comp->fgMakeEmbeddedStmt(comp->compCurBB, hiStore, parentStmt);
331340
}
332341
stmt->gtStmtILoffsx = comp->compCurStmt->gtStmt.gtStmtILoffsx;
333342
#ifdef DEBUG
@@ -378,8 +387,7 @@ void Lowering::DecomposeNode(GenTreePtr* pTree, Compiler::fgWalkData* data)
378387
assert(tree->gtOp.gtOp1->OperGet() == GT_LONG);
379388
break;
380389
case GT_STOREIND:
381-
assert(tree->gtOp.gtOp2->OperGet() == GT_LONG);
382-
NYI("StoreInd of of TYP_LONG");
390+
DecomposeStoreInd(tree);
383391
break;
384392
case GT_STORE_LCL_FLD:
385393
assert(tree->gtOp.gtOp1->OperGet() == GT_LONG);
@@ -571,6 +579,268 @@ void Lowering::DecomposeNode(GenTreePtr* pTree, Compiler::fgWalkData* data)
571579
#endif // //_TARGET_64BIT_
572580
}
573581

582+
// Decompose 64-bit storeIndir tree into multiple 32-bit trees.
583+
#if !defined(_TARGET_64BIT_)
584+
void Lowering::DecomposeStoreInd(GenTree* tree)
585+
{
586+
assert(tree->gtOp.gtOp2->OperGet() == GT_LONG);
587+
588+
GenTreeStmt* currStmt = comp->compCurStmt->AsStmt();
589+
bool isEmbeddedStmt = !currStmt->gtStmtIsTopLevel();
590+
591+
// Example input trees (a nested embedded statement case)
592+
//
593+
// <linkBegin Node>
594+
// * stmtExpr void (top level) (IL ???... ???)
595+
// | /--* argPlace ref $280
596+
// | +--* argPlace int $4a
597+
// | | { * stmtExpr void (embedded) (IL ???... ???)
598+
// | | { | /--* lclVar ref V11 tmp9 u:3 $21c
599+
// | | { | +--* const int 4 $44
600+
// | | { | /--* + byref $2c8
601+
// | | { | | { * stmtExpr void (embedded) (IL ???... ???)
602+
// | | { | | { | /--* lclFld long V01 arg1 u:2[+8] Fseq[i] $380
603+
// | | { | | { \--* st.lclVar long (P) V21 cse8
604+
// | | { | | { \--* int V21.hi (offs=0x00) -> V22 rat0
605+
// | | { | | { \--* int V21.hi (offs=0x04) -> V23 rat1
606+
// | | { | | /--* lclVar int V22 rat0 $380
607+
// | | { | | +--* lclVar int V23 rat1
608+
// | | { | +--* gt_long long
609+
// | | { \--* storeIndir long
610+
// | +--* lclVar ref V11 tmp9 u:3 (last use) $21c
611+
// | +--* lclVar ref V02 tmp0 u:3 $280
612+
// | +--* const int 8 $4a
613+
// \--* call help void HELPER.CORINFO_HELP_ARRADDR_ST $205
614+
// <linkEndNode>
615+
616+
GenTree* linkBegin = comp->fgGetFirstNode(tree)->gtPrev;
617+
GenTree* linkEnd = tree->gtNext;
618+
GenTree* gtLong = tree->gtOp.gtOp2;
619+
620+
// Save address to a temp. It is used in storeIndLow and storeIndHigh trees.
621+
GenTreeStmt* addrStmt = comp->fgInsertEmbeddedFormTemp(&tree->gtOp.gtOp1);
622+
#ifdef DEBUG
623+
if (comp->verbose)
624+
{
625+
printf("[DecomposeStoreInd]: Saving address tree to a temp var:\n");
626+
comp->gtDispTree(addrStmt);
627+
}
628+
#endif
629+
630+
// If we have made a new top-level statement, and it has inherited any
631+
// embedded statements from curStmt, they have not yet been decomposed.
632+
if (addrStmt->gtStmtIsTopLevel())
633+
{
634+
for (GenTreePtr nextEmbeddedStmt = addrStmt->gtStmtNextIfEmbedded();
635+
nextEmbeddedStmt != nullptr;
636+
nextEmbeddedStmt = nextEmbeddedStmt->gtStmt.gtStmtNextIfEmbedded())
637+
{
638+
comp->compCurStmt = nextEmbeddedStmt;
639+
comp->fgWalkTreePost(&nextEmbeddedStmt->gtStmt.gtStmtExpr, &Lowering::DecompNodeHelper, this, true);
640+
}
641+
}
642+
643+
// Restore curStmt.
644+
comp->compCurStmt = currStmt;
645+
646+
if (!gtLong->gtOp.gtOp1->OperIsLeaf())
647+
{
648+
GenTreeStmt* dataLowStmt = comp->fgInsertEmbeddedFormTemp(&gtLong->gtOp.gtOp1);
649+
#ifdef DEBUG
650+
if (comp->verbose)
651+
{
652+
printf("[DecomposeStoreInd]: Saving low data tree to a temp var:\n");
653+
comp->gtDispTree(dataLowStmt);
654+
}
655+
#endif
656+
// If we have made a new top-level statement, and it has inherited any
657+
// embedded statements from curStmt, they have not yet been decomposed.
658+
if (dataLowStmt->gtStmtIsTopLevel())
659+
{
660+
for (GenTreePtr nextEmbeddedStmt = dataLowStmt->gtStmtNextIfEmbedded();
661+
nextEmbeddedStmt != nullptr;
662+
nextEmbeddedStmt = nextEmbeddedStmt->gtStmt.gtStmtNextIfEmbedded())
663+
{
664+
comp->compCurStmt = nextEmbeddedStmt;
665+
comp->fgWalkTreePost(&nextEmbeddedStmt->gtStmt.gtStmtExpr, &Lowering::DecompNodeHelper, this, true);
666+
}
667+
}
668+
669+
// Restore curStmt.
670+
comp->compCurStmt = currStmt;
671+
}
672+
673+
if (!gtLong->gtOp.gtOp2->OperIsLeaf())
674+
{
675+
GenTreeStmt* dataHighStmt = comp->fgInsertEmbeddedFormTemp(&gtLong->gtOp.gtOp2);
676+
#ifdef DEBUG
677+
if (comp->verbose)
678+
{
679+
printf("[DecomposeStoreInd]: Saving high data tree to a temp var:\n");
680+
comp->gtDispTree(dataHighStmt);
681+
}
682+
#endif
683+
}
684+
685+
// Example trees after embedded statements for address and data are added.
686+
// This example saves all address and data trees into temp variables
687+
// to show how those embedded statements are created.
688+
//
689+
// * stmtExpr void (top level) (IL ???... ???)
690+
// | /--* argPlace ref $280
691+
// | +--* argPlace int $4a
692+
// | | { * stmtExpr void (embedded) (IL ???... ???)
693+
// | | { | /--* lclVar ref V11 tmp9 u:3 $21c
694+
// | | { | +--* const int 4 $44
695+
// | | { | /--* + byref $2c8
696+
// | | { \--* st.lclVar byref V24 rat2
697+
// | | { * stmtExpr void (embedded) (IL ???... ???)
698+
// | | { | /--* lclVar byref V24 rat2
699+
// | | { | | { * stmtExpr void (embedded) (IL ???... ???)
700+
// | | { | | { | /--* lclFld long V01 arg1 u:2[+8] Fseq[i] $380380
701+
// | | { | | { \--* st.lclVar long (P) V21 cse8
702+
// | | { | | { \--* int V21.hi (offs=0x00) -> V22 rat0
703+
// | | { | | { \--* int V21.hi (offs=0x04) -> V23 rat1
704+
// | | { | | { * stmtExpr void (embedded) (IL ???... ???)
705+
// | | { | | { | /--* lclVar int V22 rat0 $380
706+
// | | { | | { \--* st.lclVar int V25 rat3
707+
// | | { | | /--* lclVar int V25 rat3
708+
// | | { | | | { * stmtExpr void (embedded) (IL ???... ???)
709+
// | | { | | | { | /--* lclVar int V23 rat1
710+
// | | { | | | { \--* st.lclVar int V26 rat4
711+
// | | { | | +--* lclVar int V26 rat4
712+
// | | { | +--* gt_long long
713+
// | | { \--* storeIndir long
714+
// | +--* lclVar ref V11 tmp9 u:3 (last use) $21c
715+
// | +--* lclVar ref V02 tmp0 u:3 $280
716+
// | +--* const int 8 $4a
717+
// \--* call help void HELPER.CORINFO_HELP_ARRADDR_ST $205
718+
719+
GenTree* addrBase = tree->gtOp.gtOp1;
720+
GenTree* dataHigh = gtLong->gtOp.gtOp2;
721+
GenTree* dataLow = gtLong->gtOp.gtOp1;
722+
GenTree* storeIndLow = tree;
723+
724+
// Rewrite storeIndLow tree to save only lower 32-bit data.
725+
//
726+
// | | { | /--* lclVar byref V24 rat2 (address)
727+
// ...
728+
// | | { | +--* lclVar int V25 rat3 (lower 32-bit data)
729+
// | | { | { * stmtExpr void (embedded) (IL ???... ???)
730+
// | | { | { | /--* lclVar int V23 rat1
731+
// | | { | { \--* st.lclVar int V26 rat4
732+
// | | { \--* storeIndir int
733+
comp->fgSnipNode(currStmt, gtLong);
734+
comp->fgSnipNode(currStmt, dataHigh);
735+
storeIndLow->gtOp.gtOp2 = dataLow;
736+
storeIndLow->gtType = TYP_INT;
737+
738+
// Construct storeIndHigh tree
739+
//
740+
// | | { *stmtExpr void (embedded)(IL ? ? ? ... ? ? ? )
741+
// | | { | / --* lclVar int V26 rat4
742+
// | | { | | / --* lclVar byref V24 rat2
743+
// | | { | +--* lea(b + 4) ref
744+
// | | { \--* storeIndir int
745+
GenTree* addrBaseHigh = new(comp, GT_LCL_VAR) GenTreeLclVar(GT_LCL_VAR,
746+
addrBase->TypeGet(), addrBase->AsLclVarCommon()->GetLclNum(), BAD_IL_OFFSET);
747+
GenTree* addrHigh = new(comp, GT_LEA) GenTreeAddrMode(TYP_REF, addrBaseHigh, nullptr, 0, genTypeSize(TYP_INT));
748+
GenTree* storeIndHigh = new(comp, GT_STOREIND) GenTreeStoreInd(TYP_INT, addrHigh, dataHigh);
749+
storeIndHigh->gtFlags = (storeIndLow->gtFlags & (GTF_ALL_EFFECT | GTF_LIVENESS_MASK));
750+
storeIndHigh->gtFlags |= GTF_REVERSE_OPS;
751+
storeIndHigh->CopyCosts(storeIndLow);
752+
753+
// Internal links of storeIndHigh tree
754+
dataHigh->gtPrev = dataHigh->gtNext = nullptr;
755+
SimpleLinkNodeAfter(dataHigh, addrBaseHigh);
756+
SimpleLinkNodeAfter(addrBaseHigh, addrHigh);
757+
SimpleLinkNodeAfter(addrHigh, storeIndHigh);
758+
759+
// External links of storeIndHigh tree
760+
//dataHigh->gtPrev = nullptr;
761+
if (isEmbeddedStmt)
762+
{
763+
// If storeIndTree is an embedded statement, connect storeIndLow
764+
// and dataHigh
765+
storeIndLow->gtNext = dataHigh;
766+
dataHigh->gtPrev = storeIndLow;
767+
}
768+
storeIndHigh->gtNext = linkEnd;
769+
if (linkEnd != nullptr)
770+
{
771+
linkEnd->gtPrev = storeIndHigh;
772+
}
773+
774+
if (isEmbeddedStmt)
775+
{
776+
// Find a parent statment containing storeIndHigh.
777+
GenTree* parentStmt = currStmt;
778+
while ((parentStmt != nullptr) && (!parentStmt->AsStmt()->gtStmtIsTopLevel()))
779+
{
780+
parentStmt = parentStmt->gtPrev;
781+
}
782+
assert(parentStmt);
783+
784+
GenTreeStmt* stmt = comp->fgMakeEmbeddedStmt(comp->compCurBB, storeIndHigh, parentStmt);
785+
stmt->gtStmtILoffsx = comp->compCurStmt->gtStmt.gtStmtILoffsx;
786+
}
787+
else
788+
{
789+
GenTreeStmt* stmt = comp->fgNewStmtFromTree(storeIndHigh);
790+
stmt->gtStmtILoffsx = comp->compCurStmt->gtStmt.gtStmtILoffsx;
791+
792+
// Find an insert point. Skip all embedded statements.
793+
GenTree* insertPt = currStmt;
794+
while ((insertPt->gtNext != nullptr) && (!insertPt->gtNext->AsStmt()->gtStmtIsTopLevel()))
795+
{
796+
insertPt = insertPt->gtNext;
797+
}
798+
799+
comp->fgInsertStmtAfter(comp->compCurBB, insertPt, stmt);
800+
}
801+
802+
// Example final output
803+
//
804+
// * stmtExpr void (top level) (IL ???... ???)
805+
// | /--* argPlace ref $280
806+
// | +--* argPlace int $4a
807+
// | | { * stmtExpr void (embedded) (IL ???... ???)
808+
// | | { | /--* lclVar ref V11 tmp9 u:3 $21c
809+
// | | { | +--* const int 4 $44
810+
// | | { | /--* + byref $2c8
811+
// | | { \--* st.lclVar byref V24 rat2
812+
// | | { * stmtExpr void (embedded) (IL ???... ???)
813+
// | | { | /--* lclVar byref V24 rat2
814+
// | | { | | { * stmtExpr void (embedded) (IL ???... ???)
815+
// | | { | | { | /--* lclFld int V01 arg1 u:2[+8] Fseq[i] $380
816+
// | | { | | { | +--* lclFld int V01 arg1 [+12]
817+
// | | { | | { | /--* gt_long long
818+
// | | { | | { \--* st.lclVar long (P) V21 cse8
819+
// | | { | | { \--* int V21.hi (offs=0x00) -> V22 rat0
820+
// | | { | | { \--* int V21.hi (offs=0x04) -> V23 rat1
821+
// | | { | | { * stmtExpr void (embedded) (IL ???... ???)
822+
// | | { | | { | /--* lclVar int V22 rat0 $380
823+
// | | { | | { \--* st.lclVar int V25 rat3
824+
// | | { | +--* lclVar int V25 rat3
825+
// | | { | { * stmtExpr void (embedded) (IL ???... ???)
826+
// | | { | { | /--* lclVar int V23 rat1
827+
// | | { | { \--* st.lclVar int V26 rat4
828+
// | | { \--* storeIndir int
829+
// | | { * stmtExpr void (embedded) (IL ???... ???)
830+
// | | { | /--* lclVar int V26 rat4
831+
// | | { | | /--* lclVar byref V24 rat2
832+
// | | { | +--* lea(b+4) ref
833+
// | | { \--* storeIndir int
834+
// | | /--* lclVar ref V11 tmp9 u:3 (last use) $21c
835+
// | +--* putarg_stk [+0x00] ref
836+
// | | /--* lclVar ref V02 tmp0 u:3 $280
837+
// | +--* putarg_reg ref
838+
// | | /--* const int 8 $4a
839+
// | +--* putarg_reg int
840+
// \--* call help void HELPER.CORINFO_HELP_ARRADDR_ST $205
841+
}
842+
#endif //!_TARGET_64BIT_
843+
574844
/** Creates an assignment of an existing tree to a new temporary local variable
575845
* and the specified reference count for the new variable.
576846
*/
@@ -1641,7 +1911,12 @@ void Lowering::LowerCall(GenTree* node)
16411911
{
16421912
GenTreeCall* call = node->AsCall();
16431913
GenTreeStmt* callStmt = comp->compCurStmt->AsStmt();
1644-
assert(comp->fgTreeIsInStmt(call, callStmt));
1914+
//assert(comp->fgTreeIsInStmt(call, callStmt));
1915+
if (!comp->fgTreeIsInStmt(call, callStmt))
1916+
{
1917+
printf("fgTreeIsInStmt error\n");
1918+
comp->fgTreeIsInStmt(call, callStmt);
1919+
}
16451920

16461921
JITDUMP("lowering call:\n");
16471922
DISPTREE(call);
@@ -3776,7 +4051,10 @@ void Lowering::DoPhase()
37764051
currBlock = block;
37774052
comp->compCurBB = block;
37784053

3779-
/* Walk the statement trees in this basic block */
4054+
#if !defined(_TARGET_64BIT_)
4055+
// Walk the statement trees in this basic block
4056+
// Decompose all long trees first before lowering. Decomposition could
4057+
// insert statements before current statement.
37804058
for (stmt = block->bbTreeList; stmt; stmt = stmt->gtNext)
37814059
{
37824060
if (stmt->gtFlags & GTF_STMT_SKIP_LOWER)
@@ -3785,16 +4063,36 @@ void Lowering::DoPhase()
37854063
}
37864064
#ifdef DEBUG
37874065
++stmtNum;
3788-
if (comp->verbose)
4066+
if (comp->verbose)
37894067
{
37904068
// This is a useful location for a conditional breakpoint in Visual Studio (i.e. when stmtNum == 15)
3791-
printf("Lowering BB%02u, stmt %u\n", block->bbNum, stmtNum);
4069+
printf("Decomposing BB%02u, stmt %u\n", block->bbNum, stmtNum);
37924070
}
37934071
#endif
37944072
comp->compCurStmt = stmt;
3795-
#if !defined(_TARGET_64BIT_)
37964073
comp->fgWalkTreePost(&stmt->gtStmt.gtStmtExpr, &Lowering::DecompNodeHelper, this, true);
4074+
}
4075+
#endif //!_TARGET_64BIT_
4076+
4077+
#ifdef DEBUG
4078+
stmtNum = 0;
37974079
#endif
4080+
// Walk the statement trees in this basic block
4081+
for (stmt = block->bbTreeList; stmt; stmt = stmt->gtNext)
4082+
{
4083+
if (stmt->gtFlags & GTF_STMT_SKIP_LOWER)
4084+
{
4085+
continue;
4086+
}
4087+
#ifdef DEBUG
4088+
++stmtNum;
4089+
if (comp->verbose)
4090+
{
4091+
// This is a useful location for a conditional breakpoint in Visual Studio (i.e. when stmtNum == 15)
4092+
printf("Lowering BB%02u, stmt %u\n", block->bbNum, stmtNum);
4093+
}
4094+
#endif
4095+
comp->compCurStmt = stmt;
37984096
comp->fgWalkTreePost(&stmt->gtStmt.gtStmtExpr, &Lowering::LowerNodeHelper, this, true);
37994097
// We may have removed "stmt" in LowerNode().
38004098
stmt = comp->compCurStmt;

src/jit/lower.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,13 @@ class Lowering : public Phase
186186
void LowerArrElem(GenTree **ppTree, Compiler::fgWalkData* data);
187187
void LowerRotate(GenTree *tree);
188188

189+
// ------------------------------
190+
// Decompose helper functions
191+
// ------------------------------
192+
#if !defined(_TARGET_64BIT_)
193+
void DecomposeStoreInd(GenTree* tree);
194+
#endif //!_TARGET_64BIT_
195+
189196
// Utility functions
190197
void MorphBlkIntoHelperCall (GenTreePtr pTree, GenTreePtr treeStmt);
191198
public:

0 commit comments

Comments
 (0)