summaryrefslogtreecommitdiff
path: root/src/jit/emitinl.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/emitinl.h')
-rw-r--r--src/jit/emitinl.h508
1 files changed, 508 insertions, 0 deletions
diff --git a/src/jit/emitinl.h b/src/jit/emitinl.h
new file mode 100644
index 0000000000..302b8ea448
--- /dev/null
+++ b/src/jit/emitinl.h
@@ -0,0 +1,508 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+/*****************************************************************************/
+
+#ifndef _EMITINL_H_
+#define _EMITINL_H_
+/*****************************************************************************/
+/*****************************************************************************
+ *
+ * Return the number of bytes of machine code the given instruction will
+ * produce.
+ */
+
+inline UNATIVE_OFFSET emitter::emitInstCodeSz(instrDesc* id)
+{
+ return id->idCodeSize();
+}
+
+inline UNATIVE_OFFSET emitter::emitSizeOfJump(instrDescJmp* jmp)
+{
+ return jmp->idCodeSize();
+}
+
+#ifdef _TARGET_XARCH_
+
+/* static */
+inline bool emitter::instrIs3opImul(instruction ins)
+{
+#ifdef _TARGET_X86_
+ return ((ins >= INS_imul_AX) && (ins <= INS_imul_DI));
+#else // _TARGET_AMD64
+ return ((ins >= INS_imul_AX) && (ins <= INS_imul_15));
+#endif
+}
+
+/* static */
+inline bool emitter::instrIsExtendedReg3opImul(instruction ins)
+{
+#ifdef _TARGET_X86_
+ return false;
+#else // _TARGET_AMD64
+ return ((ins >= INS_imul_08) && (ins <= INS_imul_15));
+#endif
+}
+
+/* static */
+inline bool emitter::instrHasImplicitRegPairDest(instruction ins)
+{
+ return (ins == INS_mulEAX) || (ins == INS_imulEAX) || (ins == INS_div) || (ins == INS_idiv);
+}
+
+// Because we don't actually have support for encoding these 3-op
+// multiplies we fake it with special opcodes. Make sure they are
+// contiguous.
+/* static */
+inline void emitter::check3opImulValues()
+{
+ assert(INS_imul_AX - INS_imul_AX == REG_EAX);
+ assert(INS_imul_BX - INS_imul_AX == REG_EBX);
+ assert(INS_imul_CX - INS_imul_AX == REG_ECX);
+ assert(INS_imul_DX - INS_imul_AX == REG_EDX);
+ assert(INS_imul_BP - INS_imul_AX == REG_EBP);
+ assert(INS_imul_SI - INS_imul_AX == REG_ESI);
+ assert(INS_imul_DI - INS_imul_AX == REG_EDI);
+#ifdef _TARGET_AMD64_
+ assert(INS_imul_08 - INS_imul_AX == REG_R8);
+ assert(INS_imul_09 - INS_imul_AX == REG_R9);
+ assert(INS_imul_10 - INS_imul_AX == REG_R10);
+ assert(INS_imul_11 - INS_imul_AX == REG_R11);
+ assert(INS_imul_12 - INS_imul_AX == REG_R12);
+ assert(INS_imul_13 - INS_imul_AX == REG_R13);
+ assert(INS_imul_14 - INS_imul_AX == REG_R14);
+ assert(INS_imul_15 - INS_imul_AX == REG_R15);
+#endif
+}
+
+/*****************************************************************************
+ *
+ * Return the instruction that uses the given register in the imul instruction
+ */
+
+/* static */
+inline instruction emitter::inst3opImulForReg(regNumber reg)
+{
+ assert(genIsValidIntReg(reg));
+
+ instruction ins = instruction(reg + INS_imul_AX);
+ check3opImulValues();
+ assert(instrIs3opImul(ins));
+
+ return ins;
+}
+
+/*****************************************************************************
+ *
+ * Return the register which is used implicitly by the IMUL_REG instruction
+ */
+
+/* static */
+inline regNumber emitter::inst3opImulReg(instruction ins)
+{
+ regNumber reg = ((regNumber)(ins - INS_imul_AX));
+
+ assert(genIsValidIntReg(reg));
+
+ /* Make sure we return the appropriate register */
+
+ check3opImulValues();
+
+ return reg;
+}
+#endif
+
+/*****************************************************************************
+ *
+ * The following helpers should be used to access the various values that
+ * get stored in different places within the instruction descriptor.
+ */
+
+inline ssize_t emitter::emitGetInsAmd(instrDesc* id)
+{
+ return id->idIsLargeDsp() ? ((instrDescAmd*)id)->idaAmdVal : id->idAddr()->iiaAddrMode.amDisp;
+}
+
+inline int emitter::emitGetInsCDinfo(instrDesc* id)
+{
+ if (id->idIsLargeCall())
+ {
+ return ((instrDescCGCA*)id)->idcArgCnt;
+ }
+ else
+ {
+ assert(!id->idIsLargeDsp());
+ assert(!id->idIsLargeCns());
+ ssize_t cns = emitGetInsCns(id);
+
+ // We only encode 32-bit ints, so this is safe
+ noway_assert((int)cns == cns);
+
+ return (int)cns;
+ }
+}
+
+inline void emitter::emitGetInsCns(instrDesc* id, CnsVal* cv)
+{
+#ifdef RELOC_SUPPORT
+ cv->cnsReloc = id->idIsCnsReloc();
+#endif
+ if (id->idIsLargeCns())
+ {
+ cv->cnsVal = ((instrDescCns*)id)->idcCnsVal;
+ }
+ else
+ {
+ cv->cnsVal = id->idSmallCns();
+ }
+}
+
+inline ssize_t emitter::emitGetInsAmdCns(instrDesc* id, CnsVal* cv)
+{
+#ifdef RELOC_SUPPORT
+ cv->cnsReloc = id->idIsCnsReloc();
+#endif
+ if (id->idIsLargeDsp())
+ {
+ if (id->idIsLargeCns())
+ {
+ cv->cnsVal = ((instrDescCnsAmd*)id)->idacCnsVal;
+ return ((instrDescCnsAmd*)id)->idacAmdVal;
+ }
+ else
+ {
+ cv->cnsVal = id->idSmallCns();
+ return ((instrDescAmd*)id)->idaAmdVal;
+ }
+ }
+ else
+ {
+ if (id->idIsLargeCns())
+ {
+ cv->cnsVal = ((instrDescCns*)id)->idcCnsVal;
+ }
+ else
+ {
+ cv->cnsVal = id->idSmallCns();
+ }
+
+ return id->idAddr()->iiaAddrMode.amDisp;
+ }
+}
+
+inline void emitter::emitGetInsDcmCns(instrDesc* id, CnsVal* cv)
+{
+#ifdef RELOC_SUPPORT
+ cv->cnsReloc = id->idIsCnsReloc();
+#endif
+ if (id->idIsLargeCns())
+ {
+ if (id->idIsLargeDsp())
+ {
+ cv->cnsVal = ((instrDescCnsDsp*)id)->iddcCnsVal;
+ }
+ else
+ {
+ cv->cnsVal = ((instrDescCns*)id)->idcCnsVal;
+ }
+ }
+ else
+ {
+ cv->cnsVal = id->idSmallCns();
+ }
+}
+
+inline ssize_t emitter::emitGetInsAmdAny(instrDesc* id)
+{
+ if (id->idIsLargeDsp())
+ {
+ if (id->idIsLargeCns())
+ {
+ return ((instrDescCnsAmd*)id)->idacAmdVal;
+ }
+ return ((instrDescAmd*)id)->idaAmdVal;
+ }
+
+ return id->idAddr()->iiaAddrMode.amDisp;
+}
+
+/*****************************************************************************
+ *
+ * Convert between a register mask and a smaller version for storage.
+ */
+
+/*static*/ inline void emitter::emitEncodeCallGCregs(regMaskTP regmask, instrDesc* id)
+{
+ assert((regmask & RBM_CALLEE_TRASH) == 0);
+
+ unsigned encodeMask;
+
+#ifdef _TARGET_X86_
+ assert(REGNUM_BITS >= 3);
+ encodeMask = 0;
+
+ if ((regmask & RBM_ESI) != RBM_NONE)
+ encodeMask |= 0x01;
+ if ((regmask & RBM_EDI) != RBM_NONE)
+ encodeMask |= 0x02;
+ if ((regmask & RBM_EBX) != RBM_NONE)
+ encodeMask |= 0x04;
+
+ id->idReg1((regNumber)encodeMask); // Save in idReg1
+
+#elif defined(_TARGET_AMD64_)
+ assert(REGNUM_BITS >= 4);
+ encodeMask = 0;
+
+ if ((regmask & RBM_RSI) != RBM_NONE)
+ {
+ encodeMask |= 0x01;
+ }
+ if ((regmask & RBM_RDI) != RBM_NONE)
+ {
+ encodeMask |= 0x02;
+ }
+ if ((regmask & RBM_RBX) != RBM_NONE)
+ {
+ encodeMask |= 0x04;
+ }
+ if ((regmask & RBM_RBP) != RBM_NONE)
+ {
+ encodeMask |= 0x08;
+ }
+
+ id->idReg1((regNumber)encodeMask); // Save in idReg1
+
+ encodeMask = 0;
+
+ if ((regmask & RBM_R12) != RBM_NONE)
+ {
+ encodeMask |= 0x01;
+ }
+ if ((regmask & RBM_R13) != RBM_NONE)
+ {
+ encodeMask |= 0x02;
+ }
+ if ((regmask & RBM_R14) != RBM_NONE)
+ {
+ encodeMask |= 0x04;
+ }
+ if ((regmask & RBM_R15) != RBM_NONE)
+ {
+ encodeMask |= 0x08;
+ }
+
+ id->idReg2((regNumber)encodeMask); // Save in idReg2
+
+#elif defined(_TARGET_ARM_)
+ assert(REGNUM_BITS >= 4);
+ encodeMask = 0;
+
+ if ((regmask & RBM_R4) != RBM_NONE)
+ encodeMask |= 0x01;
+ if ((regmask & RBM_R5) != RBM_NONE)
+ encodeMask |= 0x02;
+ if ((regmask & RBM_R6) != RBM_NONE)
+ encodeMask |= 0x04;
+ if ((regmask & RBM_R7) != RBM_NONE)
+ encodeMask |= 0x08;
+
+ id->idReg1((regNumber)encodeMask); // Save in idReg1
+
+ encodeMask = 0;
+
+ if ((regmask & RBM_R8) != RBM_NONE)
+ encodeMask |= 0x01;
+ if ((regmask & RBM_R9) != RBM_NONE)
+ encodeMask |= 0x02;
+ if ((regmask & RBM_R10) != RBM_NONE)
+ encodeMask |= 0x04;
+ if ((regmask & RBM_R11) != RBM_NONE)
+ encodeMask |= 0x08;
+
+ id->idReg2((regNumber)encodeMask); // Save in idReg2
+
+#elif defined(_TARGET_ARM64_)
+ assert(REGNUM_BITS >= 5);
+ encodeMask = 0;
+
+ if ((regmask & RBM_R19) != RBM_NONE)
+ encodeMask |= 0x01;
+ if ((regmask & RBM_R20) != RBM_NONE)
+ encodeMask |= 0x02;
+ if ((regmask & RBM_R21) != RBM_NONE)
+ encodeMask |= 0x04;
+ if ((regmask & RBM_R22) != RBM_NONE)
+ encodeMask |= 0x08;
+ if ((regmask & RBM_R23) != RBM_NONE)
+ encodeMask |= 0x10;
+
+ id->idReg1((regNumber)encodeMask); // Save in idReg1
+
+ encodeMask = 0;
+
+ if ((regmask & RBM_R24) != RBM_NONE)
+ encodeMask |= 0x01;
+ if ((regmask & RBM_R25) != RBM_NONE)
+ encodeMask |= 0x02;
+ if ((regmask & RBM_R26) != RBM_NONE)
+ encodeMask |= 0x04;
+ if ((regmask & RBM_R27) != RBM_NONE)
+ encodeMask |= 0x08;
+ if ((regmask & RBM_R28) != RBM_NONE)
+ encodeMask |= 0x10;
+
+ id->idReg2((regNumber)encodeMask); // Save in idReg2
+
+#else
+ NYI("unknown target");
+#endif
+}
+
+/*static*/ inline unsigned emitter::emitDecodeCallGCregs(instrDesc* id)
+{
+ unsigned regmask = 0;
+ unsigned encodeMask;
+
+#ifdef _TARGET_X86_
+ assert(REGNUM_BITS >= 3);
+ encodeMask = id->idReg1();
+
+ if ((encodeMask & 0x01) != 0)
+ regmask |= RBM_ESI;
+ if ((encodeMask & 0x02) != 0)
+ regmask |= RBM_EDI;
+ if ((encodeMask & 0x04) != 0)
+ regmask |= RBM_EBX;
+#elif defined(_TARGET_AMD64_)
+ assert(REGNUM_BITS >= 4);
+ encodeMask = id->idReg1();
+
+ if ((encodeMask & 0x01) != 0)
+ {
+ regmask |= RBM_RSI;
+ }
+ if ((encodeMask & 0x02) != 0)
+ {
+ regmask |= RBM_RDI;
+ }
+ if ((encodeMask & 0x04) != 0)
+ {
+ regmask |= RBM_RBX;
+ }
+ if ((encodeMask & 0x08) != 0)
+ {
+ regmask |= RBM_RBP;
+ }
+
+ encodeMask = id->idReg2();
+
+ if ((encodeMask & 0x01) != 0)
+ {
+ regmask |= RBM_R12;
+ }
+ if ((encodeMask & 0x02) != 0)
+ {
+ regmask |= RBM_R13;
+ }
+ if ((encodeMask & 0x04) != 0)
+ {
+ regmask |= RBM_R14;
+ }
+ if ((encodeMask & 0x08) != 0)
+ {
+ regmask |= RBM_R15;
+ }
+
+#elif defined(_TARGET_ARM_)
+ assert(REGNUM_BITS >= 4);
+ encodeMask = id->idReg1();
+
+ if ((encodeMask & 0x01) != 0)
+ regmask |= RBM_R4;
+ if ((encodeMask & 0x02) != 0)
+ regmask |= RBM_R5;
+ if ((encodeMask & 0x04) != 0)
+ regmask |= RBM_R6;
+ if ((encodeMask & 0x08) != 0)
+ regmask |= RBM_R7;
+
+ encodeMask = id->idReg2();
+
+ if ((encodeMask & 0x01) != 0)
+ regmask |= RBM_R8;
+ if ((encodeMask & 0x02) != 0)
+ regmask |= RBM_R9;
+ if ((encodeMask & 0x04) != 0)
+ regmask |= RBM_R10;
+ if ((encodeMask & 0x08) != 0)
+ regmask |= RBM_R11;
+
+#elif defined(_TARGET_ARM64_)
+ assert(REGNUM_BITS >= 5);
+ encodeMask = id->idReg1();
+
+ if ((encodeMask & 0x01) != 0)
+ regmask |= RBM_R19;
+ if ((encodeMask & 0x02) != 0)
+ regmask |= RBM_R20;
+ if ((encodeMask & 0x04) != 0)
+ regmask |= RBM_R21;
+ if ((encodeMask & 0x08) != 0)
+ regmask |= RBM_R22;
+ if ((encodeMask & 0x10) != 0)
+ regmask |= RBM_R23;
+
+ encodeMask = id->idReg2();
+
+ if ((encodeMask & 0x01) != 0)
+ regmask |= RBM_R24;
+ if ((encodeMask & 0x02) != 0)
+ regmask |= RBM_R25;
+ if ((encodeMask & 0x04) != 0)
+ regmask |= RBM_R26;
+ if ((encodeMask & 0x08) != 0)
+ regmask |= RBM_R27;
+ if ((encodeMask & 0x10) != 0)
+ regmask |= RBM_R28;
+
+#else
+ NYI("unknown target");
+#endif
+
+ return regmask;
+}
+
+#ifdef _TARGET_XARCH_
+inline bool insIsCMOV(instruction ins)
+{
+ return ((ins >= INS_cmovo) && (ins <= INS_cmovg));
+}
+#endif
+
+/*****************************************************************************
+ *
+ * Call the specified function pointer for each insGroup in the current
+ * method that is marked IGF_NOGCINTERRUPT. Stops if the callback returns
+ * false. Returns the final result of the callback.
+ */
+template <typename Callback>
+bool emitter::emitGenNoGCLst(Callback& cb)
+{
+ for (insGroup* ig = emitIGlist; ig; ig = ig->igNext)
+ {
+ if (ig->igFlags & IGF_NOGCINTERRUPT)
+ {
+ if (!cb(ig->igFuncIdx, ig->igOffs, ig->igSize))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+/*****************************************************************************/
+#endif //_EMITINL_H_
+/*****************************************************************************/