summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve MacLean, Qualcomm Datacenter Technologies, Inc <sdmaclea@qti.qualcomm.com>2017-05-01 17:44:19 +0000
committerSteve MacLean, Qualcomm Datacenter Technologies, Inc <sdmaclea@qti.qualcomm.com>2017-05-08 16:23:44 +0000
commit494f00cb881cc68426718b32a62464d4c7c48007 (patch)
tree9e0fcadc82962a3358cb098a1b2f247ae316dbd5
parent487cb23e80d8cc02e21f1497d1c3c16b5ff1f367 (diff)
downloadcoreclr-494f00cb881cc68426718b32a62464d4c7c48007.tar.gz
coreclr-494f00cb881cc68426718b32a62464d4c7c48007.tar.bz2
coreclr-494f00cb881cc68426718b32a62464d4c7c48007.zip
[Arm64] Add emitIns_S_S_R_R
-rw-r--r--src/jit/codegenarm64.cpp4
-rw-r--r--src/jit/codegenarmarch.cpp7
-rw-r--r--src/jit/emit.h24
-rw-r--r--src/jit/emitarm64.cpp142
-rw-r--r--src/jit/emitarm64.h3
5 files changed, 163 insertions, 17 deletions
diff --git a/src/jit/codegenarm64.cpp b/src/jit/codegenarm64.cpp
index 8c87bc1849..0e536cd445 100644
--- a/src/jit/codegenarm64.cpp
+++ b/src/jit/codegenarm64.cpp
@@ -2638,9 +2638,7 @@ void CodeGen::genCodeForStorePairOffset(regNumber src, regNumber src2, GenTree*
if (base->gtOper == GT_LCL_FLD_ADDR)
offset += base->gtLclFld.gtLclOffs;
- // TODO-ARM64-CQ: Implement support for using a stp instruction with a varNum (see emitIns_S_R)
- emit->emitIns_S_R(INS_str, EA_8BYTE, src, base->gtLclVarCommon.gtLclNum, offset);
- emit->emitIns_S_R(INS_str, EA_8BYTE, src2, base->gtLclVarCommon.gtLclNum, offset + REGSIZE_BYTES);
+ emit->emitIns_S_S_R_R(INS_stp, EA_8BYTE, EA_8BYTE, src, src2, base->gtLclVarCommon.gtLclNum, offset);
}
else
{
diff --git a/src/jit/codegenarmarch.cpp b/src/jit/codegenarmarch.cpp
index aea4327ce2..61b9309bb9 100644
--- a/src/jit/codegenarmarch.cpp
+++ b/src/jit/codegenarmarch.cpp
@@ -735,10 +735,9 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
INS_OPTS_NONE, emitTypeSize(type0));
}
- // Emit two store instructions to store the two registers into the outgoing argument area
- emit->emitIns_S_R(ins_Store(type0), emitTypeSize(type0), loReg, varNumOut, argOffsetOut);
- emit->emitIns_S_R(ins_Store(type1), emitTypeSize(type1), hiReg, varNumOut,
- argOffsetOut + TARGET_POINTER_SIZE);
+ // Emit stp instruction to store the two registers into the outgoing argument area
+ emit->emitIns_S_S_R_R(INS_stp, emitTypeSize(type0), emitTypeSize(type1), loReg, hiReg, varNumOut,
+ argOffsetOut);
argOffsetOut += (2 * TARGET_POINTER_SIZE); // We stored 16-bytes of the struct
assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
diff --git a/src/jit/emit.h b/src/jit/emit.h
index a63242f0b0..c09953f328 100644
--- a/src/jit/emit.h
+++ b/src/jit/emit.h
@@ -885,14 +885,16 @@ protected:
void checkSizes();
union idAddrUnion {
- // TODO-Cleanup: We should really add a DEBUG-only tag to this union so we can add asserts
- // about reading what we think is here, to avoid unexpected corruption issues.
+// TODO-Cleanup: We should really add a DEBUG-only tag to this union so we can add asserts
+// about reading what we think is here, to avoid unexpected corruption issues.
+#ifndef _TARGET_ARM64_
emitLclVarAddr iiaLclVar;
- BasicBlock* iiaBBlabel;
- insGroup* iiaIGlabel;
- BYTE* iiaAddr;
- emitAddrMode iiaAddrMode;
+#endif
+ BasicBlock* iiaBBlabel;
+ insGroup* iiaIGlabel;
+ BYTE* iiaAddr;
+ emitAddrMode iiaAddrMode;
CORINFO_FIELD_HANDLE iiaFieldHnd; // iiaFieldHandle is also used to encode
// an offset into the JIT data constant area
@@ -923,11 +925,12 @@ protected:
struct
{
- regNumber _idReg3 : REGNUM_BITS;
- regNumber _idReg4 : REGNUM_BITS;
#ifdef _TARGET_ARM64_
- unsigned _idReg3Scaled : 1; // Reg3 is scaled by idOpSize bits
+ emitLclVarAddr iiaLclVar;
+ unsigned _idReg3Scaled : 1; // Reg3 is scaled by idOpSize bits
#endif
+ regNumber _idReg3 : REGNUM_BITS;
+ regNumber _idReg4 : REGNUM_BITS;
};
#elif defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
struct
@@ -2020,6 +2023,9 @@ public:
// Returns true if the instruction may write to more than one register.
bool emitInsMayWriteMultipleRegs(instrDesc* id);
+
+ // Returns "true" if instruction "id->idIns()" writes to a LclVar stack slot pair.
+ bool emitInsWritesToLclVarStackLocPair(instrDesc* id);
#endif // _TARGET_ARMARCH_
/************************************************************************/
diff --git a/src/jit/emitarm64.cpp b/src/jit/emitarm64.cpp
index e2a1ae14ec..c979c240a4 100644
--- a/src/jit/emitarm64.cpp
+++ b/src/jit/emitarm64.cpp
@@ -883,6 +883,26 @@ bool emitter::emitInsWritesToLclVarStackLoc(instrDesc* id)
}
}
+bool emitter::emitInsWritesToLclVarStackLocPair(instrDesc* id)
+{
+ if (!id->idIsLclVar())
+ return false;
+
+ instruction ins = id->idIns();
+
+ // This list is related to the list of instructions used to store local vars in emitIns_S_S_R_R().
+ // We don't accept writing to float local vars.
+
+ switch (ins)
+ {
+ case INS_stnp:
+ case INS_stp:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool emitter::emitInsMayWriteMultipleRegs(instrDesc* id)
{
instruction ins = id->idIns();
@@ -6220,6 +6240,101 @@ void emitter::emitIns_S_R(instruction ins, emitAttr attr, regNumber reg1, int va
/*****************************************************************************
*
+ * Add an instruction referencing consecutive stack-based local variable slots and two registers
+ */
+void emitter::emitIns_S_S_R_R(
+ instruction ins, emitAttr attr1, emitAttr attr2, regNumber reg1, regNumber reg2, int varx, int offs)
+{
+ assert((ins == INS_stp) || (ins == INS_stnp));
+ assert(EA_8BYTE == EA_SIZE(attr1));
+ assert(EA_8BYTE == EA_SIZE(attr2));
+ assert(isGeneralRegisterOrZR(reg1));
+ assert(isGeneralRegisterOrZR(reg2));
+ assert(offs >= 0);
+
+ emitAttr size = EA_SIZE(attr1);
+ insFormat fmt = IF_LS_3B;
+ int disp = 0;
+ const unsigned scale = 3;
+
+ /* Figure out the variable's frame position */
+ int base;
+ bool FPbased;
+
+ base = emitComp->lvaFrameAddress(varx, &FPbased);
+ disp = base + offs;
+
+ // TODO-ARM64-CQ: with compLocallocUsed, should we use REG_SAVED_LOCALLOC_SP instead?
+ regNumber reg3 = FPbased ? REG_FPBASE : REG_SPBASE;
+ reg3 = encodingSPtoZR(reg3);
+
+ bool useRegForAdr = true;
+ ssize_t imm = disp;
+ ssize_t mask = (1 << scale) - 1; // the mask of low bits that must be zero to encode the immediate
+ if (imm == 0)
+ {
+ useRegForAdr = false;
+ }
+ else
+ {
+ if ((imm & mask) == 0)
+ {
+ ssize_t immShift = imm >> scale; // The immediate is scaled by the size of the ld/st
+
+ if ((immShift >= -64) && (immShift <= 63))
+ {
+ fmt = IF_LS_3C;
+ useRegForAdr = false;
+ imm = immShift;
+ }
+ }
+ }
+
+ if (useRegForAdr)
+ {
+ regNumber rsvd = codeGen->rsGetRsvdReg();
+ emitIns_R_R_Imm(INS_add, EA_8BYTE, rsvd, reg3, imm);
+ reg3 = rsvd;
+ imm = 0;
+ }
+
+ assert(fmt != IF_NONE);
+
+ instrDesc* id = emitNewInstrCns(attr1, imm);
+
+ id->idIns(ins);
+ id->idInsFmt(fmt);
+ id->idInsOpt(INS_OPTS_NONE);
+
+ if (EA_IS_GCREF(attr2))
+ {
+ /* A special value indicates a GCref pointer value */
+
+ id->idGCrefReg2(GCT_GCREF);
+ }
+ else if (EA_IS_BYREF(attr2))
+ {
+ /* A special value indicates a Byref pointer value */
+
+ id->idGCrefReg2(GCT_BYREF);
+ }
+
+ id->idReg1(reg1);
+ id->idReg2(reg2);
+ id->idReg3(reg3);
+ id->idAddr()->iiaLclVar.initLclVarAddr(varx, offs);
+ id->idSetIsLclVar();
+
+#ifdef DEBUG
+ id->idDebugOnlyInfo()->idVarRefOffs = emitVarRefOffs;
+#endif
+
+ dispIns(id);
+ appendToCurIG(id);
+}
+
+/*****************************************************************************
+ *
* Add an instruction referencing stack-based local variable and an immediate
*/
void emitter::emitIns_S_I(instruction ins, emitAttr attr, int varx, int offs, int val)
@@ -9369,7 +9484,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
// Now we determine if the instruction has written to a (local variable) stack location, and either written a GC
// ref or overwritten one.
- if (emitInsWritesToLclVarStackLoc(id))
+ if (emitInsWritesToLclVarStackLoc(id) || emitInsWritesToLclVarStackLocPair(id))
{
int varNum = id->idAddr()->iiaLclVar.lvaVarNum();
unsigned ofs = AlignDown(id->idAddr()->iiaLclVar.lvaOffset(), sizeof(size_t));
@@ -9396,6 +9511,31 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
if (vt == TYP_REF || vt == TYP_BYREF)
emitGCvarDeadUpd(adr + ofs, dst);
}
+ if (emitInsWritesToLclVarStackLocPair(id))
+ {
+ unsigned ofs2 = ofs + sizeof(size_t);
+ if (id->idGCrefReg2() != GCT_NONE)
+ {
+ emitGCvarLiveUpd(adr + ofs2, varNum, id->idGCrefReg2(), dst);
+ }
+ else
+ {
+ // If the type of the local is a gc ref type, update the liveness.
+ var_types vt;
+ if (varNum >= 0)
+ {
+ // "Regular" (non-spill-temp) local.
+ vt = var_types(emitComp->lvaTable[varNum].lvType);
+ }
+ else
+ {
+ TempDsc* tmpDsc = emitComp->tmpFindNum(varNum);
+ vt = tmpDsc->tdTempType();
+ }
+ if (vt == TYP_REF || vt == TYP_BYREF)
+ emitGCvarDeadUpd(adr + ofs2, dst);
+ }
+ }
}
#ifdef DEBUG
diff --git a/src/jit/emitarm64.h b/src/jit/emitarm64.h
index 8dcb3286bb..87caa22638 100644
--- a/src/jit/emitarm64.h
+++ b/src/jit/emitarm64.h
@@ -758,6 +758,9 @@ void emitIns_S(instruction ins, emitAttr attr, int varx, int offs);
void emitIns_S_R(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
+void emitIns_S_S_R_R(
+ instruction ins, emitAttr attr, emitAttr attr2, regNumber ireg, regNumber ireg2, int varx, int offs);
+
void emitIns_R_S(instruction ins, emitAttr attr, regNumber ireg, int varx, int offs);
void emitIns_S_I(instruction ins, emitAttr attr, int varx, int offs, int val);