@@ -583,18 +583,17 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
583
583
{
584
584
noway_assert ((source->OperGet () == GT_LCL_VAR) || (source->OperGet () == GT_OBJ));
585
585
586
- NYI_ARM (" genPutArgStk: GT_OBJ or GT_LCL_VAR source of struct type" );
587
-
588
- #ifdef _TARGET_ARM64_
589
-
590
586
var_types targetType = source->TypeGet ();
591
587
noway_assert (varTypeIsStruct (targetType));
592
588
593
- // We will copy this struct to the stack, possibly using a ldp instruction
594
- // Setup loReg and hiReg from the internal registers that we reserved in lower.
589
+ // We will copy this struct to the stack, possibly using a ldp/ldr instruction
590
+ // in ARM64/ARM
591
+ // Setup loReg (and hiReg) from the internal registers that we reserved in lower.
595
592
//
596
- regNumber loReg = treeNode->ExtractTempReg ();
597
- regNumber hiReg = treeNode->GetSingleTempReg ();
593
+ regNumber loReg = treeNode->ExtractTempReg ();
594
+ #ifdef _TARGET_ARM64_
595
+ regNumber hiReg = treeNode->GetSingleTempReg ();
596
+ #endif // _TARGET_ARM64_
598
597
regNumber addrReg = REG_NA;
599
598
600
599
GenTreeLclVarCommon* varNode = nullptr ;
@@ -630,8 +629,10 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
630
629
// the xor ensures that only one of the two is setup, not both
631
630
assert ((varNode != nullptr ) ^ (addrNode != nullptr ));
632
631
633
- BYTE gcPtrs[MAX_ARG_REG_COUNT] = {}; // TYPE_GC_NONE = 0
634
- unsigned gcPtrCount; // The count of GC pointers in the struct
632
+ BYTE gcPtrArray[MAX_ARG_REG_COUNT] = {}; // TYPE_GC_NONE = 0
633
+ BYTE* gcPtrs = gcPtrArray;
634
+
635
+ unsigned gcPtrCount; // The count of GC pointers in the struct
635
636
int structSize;
636
637
bool isHfa;
637
638
@@ -652,10 +653,15 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
652
653
653
654
structSize = varDsc->lvSize (); // This yields the roundUp size, but that is fine
654
655
// as that is how much stack is allocated for this LclVar
655
- isHfa = varDsc->lvIsHfa ();
656
+ isHfa = varDsc->lvIsHfa ();
657
+ #ifdef _TARGET_ARM64_
656
658
gcPtrCount = varDsc->lvStructGcCount ;
657
659
for (unsigned i = 0 ; i < gcPtrCount; ++i)
658
660
gcPtrs[i] = varDsc->lvGcLayout [i];
661
+ #else // _TARGET_ARM_
662
+ gcPtrs = treeNode->gtGcPtrs ;
663
+ gcPtrCount = treeNode->gtNumSlots ;
664
+ #endif // _TARGET_ARM_
659
665
}
660
666
else // addrNode is used
661
667
{
@@ -665,13 +671,15 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
665
671
genConsumeAddress (addrNode);
666
672
addrReg = addrNode->gtRegNum ;
667
673
674
+ #ifdef _TARGET_ARM64_
668
675
// If addrReg equal to loReg, swap(loReg, hiReg)
669
676
// This reduces code complexity by only supporting one addrReg overwrite case
670
677
if (loReg == addrReg)
671
678
{
672
679
loReg = hiReg;
673
680
hiReg = addrReg;
674
681
}
682
+ #endif // _TARGET_ARM64_
675
683
676
684
CORINFO_CLASS_HANDLE objClass = source->gtObj .gtClass ;
677
685
@@ -686,21 +694,24 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
686
694
{
687
695
noway_assert (gcPtrCount == 0 );
688
696
}
697
+ #ifdef _TARGET_ARM64_
689
698
else
690
699
{
691
700
noway_assert (structSize <= 2 * TARGET_POINTER_SIZE);
692
701
}
693
702
694
703
noway_assert (structSize <= MAX_PASS_MULTIREG_BYTES);
695
-
696
- // For a >= 16-byte structSize we will generate a ldp and stp instruction each loop
697
- // ldp x2, x3, [x0]
698
- // stp x2, x3, [sp, #16]
704
+ #endif // _TARGET_ARM64_
699
705
700
706
int remainingSize = structSize;
701
707
unsigned structOffset = 0 ;
702
708
unsigned nextIndex = 0 ;
703
709
710
+ #ifdef _TARGET_ARM64_
711
+ // For a >= 16-byte structSize we will generate a ldp and stp instruction each loop
712
+ // ldp x2, x3, [x0]
713
+ // stp x2, x3, [sp, #16]
714
+
704
715
while (remainingSize >= 2 * TARGET_POINTER_SIZE)
705
716
{
706
717
var_types type0 = compiler->getJitGCType (gcPtrs[nextIndex + 0 ]);
@@ -733,20 +744,52 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
733
744
structOffset += (2 * TARGET_POINTER_SIZE);
734
745
nextIndex += 2 ;
735
746
}
747
+ #else // _TARGET_ARM_
748
+ // For a >= 4 byte structSize we will generate a ldr and str instruction each loop
749
+ // ldr r2, [r0]
750
+ // str r2, [sp, #16]
751
+ while (remainingSize >= TARGET_POINTER_SIZE)
752
+ {
753
+ var_types type = compiler->getJitGCType (gcPtrs[nextIndex]);
754
+
755
+ if (varNode != nullptr )
756
+ {
757
+ // Load from our varNumImp source
758
+ emit->emitIns_R_S (INS_ldr, emitTypeSize (type), loReg, varNumInp, 0 );
759
+ }
760
+ else
761
+ {
762
+ // check for case of destroying the addrRegister while we still need it
763
+ assert (loReg != addrReg);
764
+ noway_assert (remainingSize == TARGET_POINTER_SIZE);
765
+
766
+ // Load from our address expression source
767
+ emit->emitIns_R_R_I (INS_ldr, emitTypeSize (type), loReg, addrReg, structOffset);
768
+ }
769
+
770
+ // Emit str instruction to store the register into the outgoing argument area
771
+ emit->emitIns_S_R (INS_str, emitTypeSize (type), loReg, varNumOut, argOffsetOut);
772
+ argOffsetOut += TARGET_POINTER_SIZE; // We stored 4-bytes of the struct
773
+ assert (argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
774
+
775
+ remainingSize -= TARGET_POINTER_SIZE; // We loaded 4-bytes of the struct
776
+ structOffset += TARGET_POINTER_SIZE;
777
+ nextIndex += 1 ;
778
+ }
779
+ #endif // _TARGET_ARM_
736
780
737
781
// For a 12-byte structSize we will we will generate two load instructions
738
782
// ldr x2, [x0]
739
783
// ldr w3, [x0, #8]
740
784
// str x2, [sp, #16]
741
785
// str w3, [sp, #24]
742
786
743
- var_types nextType = compiler->getJitGCType (gcPtrs[nextIndex]);
744
- emitAttr nextAttr = emitTypeSize (nextType);
745
-
746
787
while (remainingSize > 0 )
747
788
{
748
789
if (remainingSize >= TARGET_POINTER_SIZE)
749
790
{
791
+ var_types nextType = compiler->getJitGCType (gcPtrs[nextIndex]);
792
+ emitAttr nextAttr = emitTypeSize (nextType);
750
793
remainingSize -= TARGET_POINTER_SIZE;
751
794
752
795
if (varNode != nullptr )
@@ -768,8 +811,6 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
768
811
769
812
structOffset += TARGET_POINTER_SIZE;
770
813
nextIndex++;
771
- nextType = compiler->getJitGCType (gcPtrs[nextIndex]);
772
- nextAttr = emitTypeSize (nextType);
773
814
}
774
815
else // (remainingSize < TARGET_POINTER_SIZE)
775
816
{
@@ -780,7 +821,7 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
780
821
assert (varNode == nullptr );
781
822
782
823
// the left over size is smaller than a pointer and thus can never be a GC type
783
- assert (varTypeIsGC (nextType ) == false );
824
+ assert (varTypeIsGC (compiler-> getJitGCType (gcPtrs[nextIndex]) ) == false );
784
825
785
826
var_types loadType = TYP_UINT;
786
827
if (loadSize == 1 )
@@ -810,8 +851,6 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
810
851
assert (argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
811
852
}
812
853
}
813
-
814
- #endif // _TARGET_ARM64_
815
854
}
816
855
}
817
856
}
0 commit comments