// 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_ #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. */ #ifdef _TARGET_XARCH_ 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) { cv->cnsReloc = id->idIsCnsReloc(); if (id->idIsLargeCns()) { cv->cnsVal = ((instrDescCns*)id)->idcCnsVal; } else { cv->cnsVal = id->idSmallCns(); } } inline ssize_t emitter::emitGetInsAmdCns(instrDesc* id, CnsVal* cv) { cv->cnsReloc = id->idIsCnsReloc(); 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) { cv->cnsReloc = id->idIsCnsReloc(); 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; } #endif // _TARGET_XARCH_ /***************************************************************************** * * 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 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_ /*****************************************************************************/