diff options
author | Steve MacLean, Qualcomm Datacenter Technologies, Inc <sdmaclea@qti.qualcomm.com> | 2017-05-01 17:44:19 +0000 |
---|---|---|
committer | Steve MacLean, Qualcomm Datacenter Technologies, Inc <sdmaclea@qti.qualcomm.com> | 2017-05-08 16:23:44 +0000 |
commit | 494f00cb881cc68426718b32a62464d4c7c48007 (patch) | |
tree | 9e0fcadc82962a3358cb098a1b2f247ae316dbd5 | |
parent | 487cb23e80d8cc02e21f1497d1c3c16b5ff1f367 (diff) | |
download | coreclr-494f00cb881cc68426718b32a62464d4c7c48007.tar.gz coreclr-494f00cb881cc68426718b32a62464d4c7c48007.tar.bz2 coreclr-494f00cb881cc68426718b32a62464d4c7c48007.zip |
[Arm64] Add emitIns_S_S_R_R
-rw-r--r-- | src/jit/codegenarm64.cpp | 4 | ||||
-rw-r--r-- | src/jit/codegenarmarch.cpp | 7 | ||||
-rw-r--r-- | src/jit/emit.h | 24 | ||||
-rw-r--r-- | src/jit/emitarm64.cpp | 142 | ||||
-rw-r--r-- | src/jit/emitarm64.h | 3 |
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); |