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

Commit 4349824

Browse files
hseok-ohBruceForstall
authored andcommitted
[ARM32/RyuJIT] Enable passing struct argument that use stack only (#11541)
* [ARM32/RyuJIT] Enable passing struct argument that use stack only Enable passing struct argument when it uses stack only. Cannot pass splitted struct argument that uses stack and register(s) yet. * Remove redundant GC type assignment and fix internal register count - Remove redundant GC type assignment in genPutArgStk - Fix internal register count for ARM32: 2 -> 1
1 parent 5493b84 commit 4349824

File tree

3 files changed

+68
-23
lines changed

3 files changed

+68
-23
lines changed

src/jit/codegenarmarch.cpp

Lines changed: 62 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -583,18 +583,17 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
583583
{
584584
noway_assert((source->OperGet() == GT_LCL_VAR) || (source->OperGet() == GT_OBJ));
585585

586-
NYI_ARM("genPutArgStk: GT_OBJ or GT_LCL_VAR source of struct type");
587-
588-
#ifdef _TARGET_ARM64_
589-
590586
var_types targetType = source->TypeGet();
591587
noway_assert(varTypeIsStruct(targetType));
592588

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.
595592
//
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_
598597
regNumber addrReg = REG_NA;
599598

600599
GenTreeLclVarCommon* varNode = nullptr;
@@ -630,8 +629,10 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
630629
// the xor ensures that only one of the two is setup, not both
631630
assert((varNode != nullptr) ^ (addrNode != nullptr));
632631

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
635636
int structSize;
636637
bool isHfa;
637638

@@ -652,10 +653,15 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
652653

653654
structSize = varDsc->lvSize(); // This yields the roundUp size, but that is fine
654655
// as that is how much stack is allocated for this LclVar
655-
isHfa = varDsc->lvIsHfa();
656+
isHfa = varDsc->lvIsHfa();
657+
#ifdef _TARGET_ARM64_
656658
gcPtrCount = varDsc->lvStructGcCount;
657659
for (unsigned i = 0; i < gcPtrCount; ++i)
658660
gcPtrs[i] = varDsc->lvGcLayout[i];
661+
#else // _TARGET_ARM_
662+
gcPtrs = treeNode->gtGcPtrs;
663+
gcPtrCount = treeNode->gtNumSlots;
664+
#endif // _TARGET_ARM_
659665
}
660666
else // addrNode is used
661667
{
@@ -665,13 +671,15 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
665671
genConsumeAddress(addrNode);
666672
addrReg = addrNode->gtRegNum;
667673

674+
#ifdef _TARGET_ARM64_
668675
// If addrReg equal to loReg, swap(loReg, hiReg)
669676
// This reduces code complexity by only supporting one addrReg overwrite case
670677
if (loReg == addrReg)
671678
{
672679
loReg = hiReg;
673680
hiReg = addrReg;
674681
}
682+
#endif // _TARGET_ARM64_
675683

676684
CORINFO_CLASS_HANDLE objClass = source->gtObj.gtClass;
677685

@@ -686,21 +694,24 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
686694
{
687695
noway_assert(gcPtrCount == 0);
688696
}
697+
#ifdef _TARGET_ARM64_
689698
else
690699
{
691700
noway_assert(structSize <= 2 * TARGET_POINTER_SIZE);
692701
}
693702

694703
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_
699705

700706
int remainingSize = structSize;
701707
unsigned structOffset = 0;
702708
unsigned nextIndex = 0;
703709

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+
704715
while (remainingSize >= 2 * TARGET_POINTER_SIZE)
705716
{
706717
var_types type0 = compiler->getJitGCType(gcPtrs[nextIndex + 0]);
@@ -733,20 +744,52 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
733744
structOffset += (2 * TARGET_POINTER_SIZE);
734745
nextIndex += 2;
735746
}
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_
736780

737781
// For a 12-byte structSize we will we will generate two load instructions
738782
// ldr x2, [x0]
739783
// ldr w3, [x0, #8]
740784
// str x2, [sp, #16]
741785
// str w3, [sp, #24]
742786

743-
var_types nextType = compiler->getJitGCType(gcPtrs[nextIndex]);
744-
emitAttr nextAttr = emitTypeSize(nextType);
745-
746787
while (remainingSize > 0)
747788
{
748789
if (remainingSize >= TARGET_POINTER_SIZE)
749790
{
791+
var_types nextType = compiler->getJitGCType(gcPtrs[nextIndex]);
792+
emitAttr nextAttr = emitTypeSize(nextType);
750793
remainingSize -= TARGET_POINTER_SIZE;
751794

752795
if (varNode != nullptr)
@@ -768,8 +811,6 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
768811

769812
structOffset += TARGET_POINTER_SIZE;
770813
nextIndex++;
771-
nextType = compiler->getJitGCType(gcPtrs[nextIndex]);
772-
nextAttr = emitTypeSize(nextType);
773814
}
774815
else // (remainingSize < TARGET_POINTER_SIZE)
775816
{
@@ -780,7 +821,7 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
780821
assert(varNode == nullptr);
781822

782823
// 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);
784825

785826
var_types loadType = TYP_UINT;
786827
if (loadSize == 1)
@@ -810,8 +851,6 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
810851
assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
811852
}
812853
}
813-
814-
#endif // _TARGET_ARM64_
815854
}
816855
}
817856
}

src/jit/lsraarm.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,7 @@ void Lowering::TreeNodeInfoInit(GenTree* tree)
740740
case GT_PINVOKE_PROLOG:
741741
case GT_JCC:
742742
case GT_MEMORYBARRIER:
743+
case GT_OBJ:
743744
info->dstCount = tree->IsValue() ? 1 : 0;
744745
if (kind & (GTK_CONST | GTK_LEAF))
745746
{

src/jit/lsraarmarch.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,8 +654,13 @@ void Lowering::TreeNodeInfoInitPutArgStk(GenTreePutArgStk* argNode, fgArgTabEntr
654654
}
655655
else
656656
{
657+
#ifdef _TARGET_ARM64_
657658
// We could use a ldp/stp sequence so we need two internal registers
658659
argNode->gtLsraInfo.internalIntCount = 2;
660+
#else // _TARGET_ARM_
661+
// We could use a ldr/str sequence so we need a internal register
662+
argNode->gtLsraInfo.internalIntCount = 1;
663+
#endif // _TARGET_ARM_
659664

660665
if (putArgChild->OperGet() == GT_OBJ)
661666
{

0 commit comments

Comments
 (0)