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

Commit 494f00c

Browse files
committed
[Arm64] Add emitIns_S_S_R_R
1 parent 487cb23 commit 494f00c

File tree

5 files changed

+163
-17
lines changed

5 files changed

+163
-17
lines changed

src/jit/codegenarm64.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2638,9 +2638,7 @@ void CodeGen::genCodeForStorePairOffset(regNumber src, regNumber src2, GenTree*
26382638
if (base->gtOper == GT_LCL_FLD_ADDR)
26392639
offset += base->gtLclFld.gtLclOffs;
26402640

2641-
// TODO-ARM64-CQ: Implement support for using a stp instruction with a varNum (see emitIns_S_R)
2642-
emit->emitIns_S_R(INS_str, EA_8BYTE, src, base->gtLclVarCommon.gtLclNum, offset);
2643-
emit->emitIns_S_R(INS_str, EA_8BYTE, src2, base->gtLclVarCommon.gtLclNum, offset + REGSIZE_BYTES);
2641+
emit->emitIns_S_S_R_R(INS_stp, EA_8BYTE, EA_8BYTE, src, src2, base->gtLclVarCommon.gtLclNum, offset);
26442642
}
26452643
else
26462644
{

src/jit/codegenarmarch.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -735,10 +735,9 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
735735
INS_OPTS_NONE, emitTypeSize(type0));
736736
}
737737

738-
// Emit two store instructions to store the two registers into the outgoing argument area
739-
emit->emitIns_S_R(ins_Store(type0), emitTypeSize(type0), loReg, varNumOut, argOffsetOut);
740-
emit->emitIns_S_R(ins_Store(type1), emitTypeSize(type1), hiReg, varNumOut,
741-
argOffsetOut + TARGET_POINTER_SIZE);
738+
// Emit stp instruction to store the two registers into the outgoing argument area
739+
emit->emitIns_S_S_R_R(INS_stp, emitTypeSize(type0), emitTypeSize(type1), loReg, hiReg, varNumOut,
740+
argOffsetOut);
742741
argOffsetOut += (2 * TARGET_POINTER_SIZE); // We stored 16-bytes of the struct
743742
assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
744743

src/jit/emit.h

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -885,14 +885,16 @@ class emitter
885885
void checkSizes();
886886

887887
union idAddrUnion {
888-
// TODO-Cleanup: We should really add a DEBUG-only tag to this union so we can add asserts
889-
// about reading what we think is here, to avoid unexpected corruption issues.
888+
// TODO-Cleanup: We should really add a DEBUG-only tag to this union so we can add asserts
889+
// about reading what we think is here, to avoid unexpected corruption issues.
890890

891+
#ifndef _TARGET_ARM64_
891892
emitLclVarAddr iiaLclVar;
892-
BasicBlock* iiaBBlabel;
893-
insGroup* iiaIGlabel;
894-
BYTE* iiaAddr;
895-
emitAddrMode iiaAddrMode;
893+
#endif
894+
BasicBlock* iiaBBlabel;
895+
insGroup* iiaIGlabel;
896+
BYTE* iiaAddr;
897+
emitAddrMode iiaAddrMode;
896898

897899
CORINFO_FIELD_HANDLE iiaFieldHnd; // iiaFieldHandle is also used to encode
898900
// an offset into the JIT data constant area
@@ -923,11 +925,12 @@ class emitter
923925

924926
struct
925927
{
926-
regNumber _idReg3 : REGNUM_BITS;
927-
regNumber _idReg4 : REGNUM_BITS;
928928
#ifdef _TARGET_ARM64_
929-
unsigned _idReg3Scaled : 1; // Reg3 is scaled by idOpSize bits
929+
emitLclVarAddr iiaLclVar;
930+
unsigned _idReg3Scaled : 1; // Reg3 is scaled by idOpSize bits
930931
#endif
932+
regNumber _idReg3 : REGNUM_BITS;
933+
regNumber _idReg4 : REGNUM_BITS;
931934
};
932935
#elif defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
933936
struct
@@ -2020,6 +2023,9 @@ class emitter
20202023

20212024
// Returns true if the instruction may write to more than one register.
20222025
bool emitInsMayWriteMultipleRegs(instrDesc* id);
2026+
2027+
// Returns "true" if instruction "id->idIns()" writes to a LclVar stack slot pair.
2028+
bool emitInsWritesToLclVarStackLocPair(instrDesc* id);
20232029
#endif // _TARGET_ARMARCH_
20242030

20252031
/************************************************************************/

src/jit/emitarm64.cpp

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,26 @@ bool emitter::emitInsWritesToLclVarStackLoc(instrDesc* id)
883883
}
884884
}
885885

886+
bool emitter::emitInsWritesToLclVarStackLocPair(instrDesc* id)
887+
{
888+
if (!id->idIsLclVar())
889+
return false;
890+
891+
instruction ins = id->idIns();
892+
893+
// This list is related to the list of instructions used to store local vars in emitIns_S_S_R_R().
894+
// We don't accept writing to float local vars.
895+
896+
switch (ins)
897+
{
898+
case INS_stnp:
899+
case INS_stp:
900+
return true;
901+
default:
902+
return false;
903+
}
904+
}
905+
886906
bool emitter::emitInsMayWriteMultipleRegs(instrDesc* id)
887907
{
888908
instruction ins = id->idIns();
@@ -6218,6 +6238,101 @@ void emitter::emitIns_S_R(instruction ins, emitAttr attr, regNumber reg1, int va
62186238
appendToCurIG(id);
62196239
}
62206240

6241+
/*****************************************************************************
6242+
*
6243+
* Add an instruction referencing consecutive stack-based local variable slots and two registers
6244+
*/
6245+
void emitter::emitIns_S_S_R_R(
6246+
instruction ins, emitAttr attr1, emitAttr attr2, regNumber reg1, regNumber reg2, int varx, int offs)
6247+
{
6248+
assert((ins == INS_stp) || (ins == INS_stnp));
6249+
assert(EA_8BYTE == EA_SIZE(attr1));
6250+
assert(EA_8BYTE == EA_SIZE(attr2));
6251+
assert(isGeneralRegisterOrZR(reg1));
6252+
assert(isGeneralRegisterOrZR(reg2));
6253+
assert(offs >= 0);
6254+
6255+
emitAttr size = EA_SIZE(attr1);
6256+
insFormat fmt = IF_LS_3B;
6257+
int disp = 0;
6258+
const unsigned scale = 3;
6259+
6260+
/* Figure out the variable's frame position */
6261+
int base;
6262+
bool FPbased;
6263+
6264+
base = emitComp->lvaFrameAddress(varx, &FPbased);
6265+
disp = base + offs;
6266+
6267+
// TODO-ARM64-CQ: with compLocallocUsed, should we use REG_SAVED_LOCALLOC_SP instead?
6268+
regNumber reg3 = FPbased ? REG_FPBASE : REG_SPBASE;
6269+
reg3 = encodingSPtoZR(reg3);
6270+
6271+
bool useRegForAdr = true;
6272+
ssize_t imm = disp;
6273+
ssize_t mask = (1 << scale) - 1; // the mask of low bits that must be zero to encode the immediate
6274+
if (imm == 0)
6275+
{
6276+
useRegForAdr = false;
6277+
}
6278+
else
6279+
{
6280+
if ((imm & mask) == 0)
6281+
{
6282+
ssize_t immShift = imm >> scale; // The immediate is scaled by the size of the ld/st
6283+
6284+
if ((immShift >= -64) && (immShift <= 63))
6285+
{
6286+
fmt = IF_LS_3C;
6287+
useRegForAdr = false;
6288+
imm = immShift;
6289+
}
6290+
}
6291+
}
6292+
6293+
if (useRegForAdr)
6294+
{
6295+
regNumber rsvd = codeGen->rsGetRsvdReg();
6296+
emitIns_R_R_Imm(INS_add, EA_8BYTE, rsvd, reg3, imm);
6297+
reg3 = rsvd;
6298+
imm = 0;
6299+
}
6300+
6301+
assert(fmt != IF_NONE);
6302+
6303+
instrDesc* id = emitNewInstrCns(attr1, imm);
6304+
6305+
id->idIns(ins);
6306+
id->idInsFmt(fmt);
6307+
id->idInsOpt(INS_OPTS_NONE);
6308+
6309+
if (EA_IS_GCREF(attr2))
6310+
{
6311+
/* A special value indicates a GCref pointer value */
6312+
6313+
id->idGCrefReg2(GCT_GCREF);
6314+
}
6315+
else if (EA_IS_BYREF(attr2))
6316+
{
6317+
/* A special value indicates a Byref pointer value */
6318+
6319+
id->idGCrefReg2(GCT_BYREF);
6320+
}
6321+
6322+
id->idReg1(reg1);
6323+
id->idReg2(reg2);
6324+
id->idReg3(reg3);
6325+
id->idAddr()->iiaLclVar.initLclVarAddr(varx, offs);
6326+
id->idSetIsLclVar();
6327+
6328+
#ifdef DEBUG
6329+
id->idDebugOnlyInfo()->idVarRefOffs = emitVarRefOffs;
6330+
#endif
6331+
6332+
dispIns(id);
6333+
appendToCurIG(id);
6334+
}
6335+
62216336
/*****************************************************************************
62226337
*
62236338
* Add an instruction referencing stack-based local variable and an immediate
@@ -9369,7 +9484,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
93699484

93709485
// Now we determine if the instruction has written to a (local variable) stack location, and either written a GC
93719486
// ref or overwritten one.
9372-
if (emitInsWritesToLclVarStackLoc(id))
9487+
if (emitInsWritesToLclVarStackLoc(id) || emitInsWritesToLclVarStackLocPair(id))
93739488
{
93749489
int varNum = id->idAddr()->iiaLclVar.lvaVarNum();
93759490
unsigned ofs = AlignDown(id->idAddr()->iiaLclVar.lvaOffset(), sizeof(size_t));
@@ -9396,6 +9511,31 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
93969511
if (vt == TYP_REF || vt == TYP_BYREF)
93979512
emitGCvarDeadUpd(adr + ofs, dst);
93989513
}
9514+
if (emitInsWritesToLclVarStackLocPair(id))
9515+
{
9516+
unsigned ofs2 = ofs + sizeof(size_t);
9517+
if (id->idGCrefReg2() != GCT_NONE)
9518+
{
9519+
emitGCvarLiveUpd(adr + ofs2, varNum, id->idGCrefReg2(), dst);
9520+
}
9521+
else
9522+
{
9523+
// If the type of the local is a gc ref type, update the liveness.
9524+
var_types vt;
9525+
if (varNum >= 0)
9526+
{
9527+
// "Regular" (non-spill-temp) local.
9528+
vt = var_types(emitComp->lvaTable[varNum].lvType);
9529+
}
9530+
else
9531+
{
9532+
TempDsc* tmpDsc = emitComp->tmpFindNum(varNum);
9533+
vt = tmpDsc->tdTempType();
9534+
}
9535+
if (vt == TYP_REF || vt == TYP_BYREF)
9536+
emitGCvarDeadUpd(adr + ofs2, dst);
9537+
}
9538+
}
93999539
}
94009540

94019541
#ifdef DEBUG

src/jit/emitarm64.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,9 @@ void emitIns_S(instruction ins, emitAttr attr, int varx, int offs);
758758

759759
void emitIns_S_R(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
760760

761+
void emitIns_S_S_R_R(
762+
instruction ins, emitAttr attr, emitAttr attr2, regNumber ireg, regNumber ireg2, int varx, int offs);
763+
761764
void emitIns_R_S(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
762765

763766
void emitIns_S_I(instruction ins, emitAttr attr, int varx, int offs, int val);

0 commit comments

Comments
 (0)