@@ -308,6 +308,7 @@ void Lowering::DecomposeNode(GenTreePtr* pTree, Compiler::fgWalkData* data)
308
308
comp->lvaIncRefCnts (tree);
309
309
comp->lvaIncRefCnts (hiStore);
310
310
311
+ tree->gtNext = hiRhs;
311
312
hiRhs->gtPrev = tree;
312
313
hiRhs->gtNext = hiStore;
313
314
hiStore->gtPrev = hiRhs;
@@ -318,7 +319,9 @@ void Lowering::DecomposeNode(GenTreePtr* pTree, Compiler::fgWalkData* data)
318
319
}
319
320
nextTree = hiRhs;
320
321
GenTreeStmt* stmt;
321
- if (comp->compCurStmt ->gtStmt .gtStmtExpr == tree)
322
+ GenTreeStmt* currStmt = comp->compCurStmt ->AsStmt ();
323
+ bool isEmbeddedStmt = !currStmt->gtStmtIsTopLevel ();
324
+ if (!isEmbeddedStmt)
322
325
{
323
326
tree->gtNext = nullptr ;
324
327
hiRhs->gtPrev = nullptr ;
@@ -327,7 +330,13 @@ void Lowering::DecomposeNode(GenTreePtr* pTree, Compiler::fgWalkData* data)
327
330
}
328
331
else
329
332
{
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);
331
340
}
332
341
stmt->gtStmtILoffsx = comp->compCurStmt ->gtStmt .gtStmtILoffsx ;
333
342
#ifdef DEBUG
@@ -378,8 +387,7 @@ void Lowering::DecomposeNode(GenTreePtr* pTree, Compiler::fgWalkData* data)
378
387
assert (tree->gtOp .gtOp1 ->OperGet () == GT_LONG);
379
388
break ;
380
389
case GT_STOREIND:
381
- assert (tree->gtOp .gtOp2 ->OperGet () == GT_LONG);
382
- NYI (" StoreInd of of TYP_LONG" );
390
+ DecomposeStoreInd (tree);
383
391
break ;
384
392
case GT_STORE_LCL_FLD:
385
393
assert (tree->gtOp .gtOp1 ->OperGet () == GT_LONG);
@@ -571,6 +579,268 @@ void Lowering::DecomposeNode(GenTreePtr* pTree, Compiler::fgWalkData* data)
571
579
#endif // //_TARGET_64BIT_
572
580
}
573
581
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 (>Long->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 (>Long->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
+
574
844
/* * Creates an assignment of an existing tree to a new temporary local variable
575
845
* and the specified reference count for the new variable.
576
846
*/
@@ -1641,7 +1911,12 @@ void Lowering::LowerCall(GenTree* node)
1641
1911
{
1642
1912
GenTreeCall* call = node->AsCall ();
1643
1913
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
+ }
1645
1920
1646
1921
JITDUMP (" lowering call:\n " );
1647
1922
DISPTREE (call);
@@ -3776,7 +4051,10 @@ void Lowering::DoPhase()
3776
4051
currBlock = block;
3777
4052
comp->compCurBB = block;
3778
4053
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.
3780
4058
for (stmt = block->bbTreeList ; stmt; stmt = stmt->gtNext )
3781
4059
{
3782
4060
if (stmt->gtFlags & GTF_STMT_SKIP_LOWER)
@@ -3785,16 +4063,36 @@ void Lowering::DoPhase()
3785
4063
}
3786
4064
#ifdef DEBUG
3787
4065
++stmtNum;
3788
- if (comp->verbose )
4066
+ if (comp->verbose )
3789
4067
{
3790
4068
// 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);
3792
4070
}
3793
4071
#endif
3794
4072
comp->compCurStmt = stmt;
3795
- #if !defined(_TARGET_64BIT_)
3796
4073
comp->fgWalkTreePost (&stmt->gtStmt .gtStmtExpr , &Lowering::DecompNodeHelper, this , true );
4074
+ }
4075
+ #endif // !_TARGET_64BIT_
4076
+
4077
+ #ifdef DEBUG
4078
+ stmtNum = 0 ;
3797
4079
#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;
3798
4096
comp->fgWalkTreePost (&stmt->gtStmt .gtStmtExpr , &Lowering::LowerNodeHelper, this , true );
3799
4097
// We may have removed "stmt" in LowerNode().
3800
4098
stmt = comp->compCurStmt ;
0 commit comments