diff options
Diffstat (limited to 'src/jit/emitxarch.h')
-rw-r--r-- | src/jit/emitxarch.h | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/src/jit/emitxarch.h b/src/jit/emitxarch.h new file mode 100644 index 0000000000..dfd7e6ec50 --- /dev/null +++ b/src/jit/emitxarch.h @@ -0,0 +1,437 @@ +// 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. + +#if defined(_TARGET_XARCH_) + +/************************************************************************/ +/* Public inline informational methods */ +/************************************************************************/ + +public: +inline static bool isGeneralRegister(regNumber reg) +{ + return (reg <= REG_INT_LAST); +} + +inline static bool isFloatReg(regNumber reg) +{ + return (reg >= REG_FP_FIRST && reg <= REG_FP_LAST); +} + +inline static bool isDoubleReg(regNumber reg) +{ + return isFloatReg(reg); +} + +/************************************************************************/ +/* Routines that compute the size of / encode instructions */ +/************************************************************************/ + +struct CnsVal +{ + ssize_t cnsVal; +#ifdef RELOC_SUPPORT + bool cnsReloc; +#endif +}; + +UNATIVE_OFFSET emitInsSize(size_t code); +UNATIVE_OFFSET emitInsSizeRM(instruction ins); +UNATIVE_OFFSET emitInsSizeSV(size_t code, int var, int dsp); +UNATIVE_OFFSET emitInsSizeSV(instrDesc* id, int var, int dsp, int val); +UNATIVE_OFFSET emitInsSizeRR(instruction ins, regNumber reg1, regNumber reg2, emitAttr attr); +UNATIVE_OFFSET emitInsSizeAM(instrDesc* id, size_t code); +UNATIVE_OFFSET emitInsSizeAM(instrDesc* id, size_t code, int val); +UNATIVE_OFFSET emitInsSizeCV(instrDesc* id, size_t code); +UNATIVE_OFFSET emitInsSizeCV(instrDesc* id, size_t code, int val); + +BYTE* emitOutputAM(BYTE* dst, instrDesc* id, size_t code, CnsVal* addc = nullptr); +BYTE* emitOutputSV(BYTE* dst, instrDesc* id, size_t code, CnsVal* addc = nullptr); +BYTE* emitOutputCV(BYTE* dst, instrDesc* id, size_t code, CnsVal* addc = nullptr); + +BYTE* emitOutputR(BYTE* dst, instrDesc* id); +BYTE* emitOutputRI(BYTE* dst, instrDesc* id); +BYTE* emitOutputRR(BYTE* dst, instrDesc* id); +BYTE* emitOutputIV(BYTE* dst, instrDesc* id); + +#ifdef FEATURE_AVX_SUPPORT +BYTE* emitOutputRRR(BYTE* dst, instrDesc* id); +#endif + +BYTE* emitOutputLJ(BYTE* dst, instrDesc* id); + +unsigned emitOutputRexOrVexPrefixIfNeeded(instruction ins, BYTE* dst, size_t& code); +unsigned emitGetRexPrefixSize(instruction ins); +unsigned emitGetVexPrefixSize(instruction ins, emitAttr attr); +unsigned emitGetPrefixSize(size_t code); +unsigned emitGetVexPrefixAdjustedSize(instruction ins, emitAttr attr, size_t code); + +unsigned insEncodeReg345(instruction ins, regNumber reg, emitAttr size, size_t* code); +unsigned insEncodeReg012(instruction ins, regNumber reg, emitAttr size, size_t* code); +size_t insEncodeReg3456(instruction ins, regNumber reg, emitAttr size, size_t code); +unsigned insEncodeRegSIB(instruction ins, regNumber reg, size_t* code); + +size_t insEncodeMRreg(instruction ins, size_t code); +size_t insEncodeMRreg(instruction ins, regNumber reg, emitAttr size, size_t code); +size_t insEncodeRRIb(instruction ins, regNumber reg, emitAttr size); +size_t insEncodeOpreg(instruction ins, regNumber reg, emitAttr size); + +bool IsAVXInstruction(instruction ins); +size_t insEncodeMIreg(instruction ins, regNumber reg, emitAttr size, size_t code); + +size_t AddRexWPrefix(instruction ins, size_t code); +size_t AddRexRPrefix(instruction ins, size_t code); +size_t AddRexXPrefix(instruction ins, size_t code); +size_t AddRexBPrefix(instruction ins, size_t code); +size_t AddRexPrefix(instruction ins, size_t code); + +#ifdef FEATURE_AVX_SUPPORT +// 3-byte VEX prefix starts with byte 0xC4 +#define VEX_PREFIX_MASK_3BYTE 0xC4000000000000LL +bool TakesVexPrefix(instruction ins); +// Returns true if the instruction encoding already contains VEX prefix +bool hasVexPrefix(size_t code) +{ + return (code & VEX_PREFIX_MASK_3BYTE) != 0; +} +size_t AddVexPrefix(instruction ins, size_t code, emitAttr attr); +size_t AddVexPrefixIfNeeded(instruction ins, size_t code, emitAttr size) +{ + if (TakesVexPrefix(ins)) + { + code = AddVexPrefix(ins, code, size); + } + return code; +} +size_t AddVexPrefixIfNeededAndNotPresent(instruction ins, size_t code, emitAttr size) +{ + if (TakesVexPrefix(ins) && !hasVexPrefix(code)) + { + code = AddVexPrefix(ins, code, size); + } + return code; +} +bool useAVXEncodings; +bool UseAVX() +{ + return useAVXEncodings; +} +void SetUseAVX(bool value) +{ + useAVXEncodings = value; +} +bool IsThreeOperandBinaryAVXInstruction(instruction ins); +bool IsThreeOperandMoveAVXInstruction(instruction ins); +bool IsThreeOperandAVXInstruction(instruction ins) +{ + return (IsThreeOperandBinaryAVXInstruction(ins) || IsThreeOperandMoveAVXInstruction(ins)); +} +#else // !FEATURE_AVX_SUPPORT +bool UseAVX() +{ + return false; +} +bool hasVexPrefix(size_t code) +{ + return false; +} +bool IsThreeOperandBinaryAVXInstruction(instruction ins) +{ + return false; +} +bool IsThreeOperandMoveAVXInstruction(instruction ins) +{ + return false; +} +bool IsThreeOperandAVXInstruction(instruction ins) +{ + return false; +} +bool TakesVexPrefix(instruction ins) +{ + return false; +} +size_t AddVexPrefixIfNeeded(instruction ins, size_t code, emitAttr attr) +{ + return code; +} +size_t AddVexPrefixIfNeededAndNotPresent(instruction ins, size_t code, emitAttr size) +{ + return code; +} +#endif // !FEATURE_AVX_SUPPORT + +/************************************************************************/ +/* Debug-only routines to display instructions */ +/************************************************************************/ + +#ifdef DEBUG + +const char* emitFPregName(unsigned reg, bool varName = true); + +void emitDispReloc(ssize_t value); +void emitDispAddrMode(instrDesc* id, bool noDetail = false); +void emitDispShift(instruction ins, int cnt = 0); + +void emitDispIns(instrDesc* id, + bool isNew, + bool doffs, + bool asmfm, + unsigned offs = 0, + BYTE* code = nullptr, + size_t sz = 0, + insGroup* ig = nullptr); + +const char* emitXMMregName(unsigned reg); +const char* emitYMMregName(unsigned reg); + +#endif + +/************************************************************************/ +/* Private members that deal with target-dependent instr. descriptors */ +/************************************************************************/ + +private: +void emitSetAmdDisp(instrDescAmd* id, ssize_t dsp); +instrDesc* emitNewInstrAmd(emitAttr attr, ssize_t dsp); +instrDesc* emitNewInstrAmdCns(emitAttr attr, ssize_t dsp, int cns); + +instrDesc* emitNewInstrCallDir(int argCnt, + VARSET_VALARG_TP GCvars, + regMaskTP gcrefRegs, + regMaskTP byrefRegs, + emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize)); + +instrDesc* emitNewInstrCallInd(int argCnt, + ssize_t disp, + VARSET_VALARG_TP GCvars, + regMaskTP gcrefRegs, + regMaskTP byrefRegs, + emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize)); + +void emitGetInsCns(instrDesc* id, CnsVal* cv); +ssize_t emitGetInsAmdCns(instrDesc* id, CnsVal* cv); +void emitGetInsDcmCns(instrDesc* id, CnsVal* cv); +ssize_t emitGetInsAmdAny(instrDesc* id); + +/************************************************************************/ +/* Private helpers for instruction output */ +/************************************************************************/ + +private: +insFormat emitInsModeFormat(instruction ins, insFormat base, insFormat FPld, insFormat FPst); + +bool emitVerifyEncodable(instruction ins, emitAttr size, regNumber reg1, regNumber reg2 = REG_NA); + +bool emitInsCanOnlyWriteSSE2OrAVXReg(instrDesc* id); + +/***************************************************************************** +* +* Convert between an index scale in bytes to a smaller encoding used for +* storage in instruction descriptors. +*/ + +inline emitter::opSize emitEncodeScale(size_t scale) +{ + assert(scale == 1 || scale == 2 || scale == 4 || scale == 8); + + return emitSizeEncode[scale - 1]; +} + +inline emitAttr emitDecodeScale(unsigned ensz) +{ + assert(ensz < 4); + + return emitter::emitSizeDecode[ensz]; +} + +/************************************************************************/ +/* The public entry points to output instructions */ +/************************************************************************/ + +public: +void emitLoopAlign(); + +void emitIns(instruction ins); + +void emitIns(instruction ins, emitAttr attr); + +void emitInsRMW(instruction inst, emitAttr attr, GenTreeStoreInd* storeInd, GenTreePtr src); + +void emitInsRMW(instruction inst, emitAttr attr, GenTreeStoreInd* storeInd); + +void emitIns_Nop(unsigned size); + +void emitIns_I(instruction ins, emitAttr attr, int val); + +void emitIns_R(instruction ins, emitAttr attr, regNumber reg); + +void emitIns_C(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fdlHnd, int offs); + +void emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t val); + +void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2); + +void emitIns_R_R_I(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, int ival); + +#ifdef FEATURE_AVX_SUPPORT +void emitIns_R_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3); +#endif + +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_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); + +void emitIns_R_C(instruction ins, emitAttr attr, regNumber reg, CORINFO_FIELD_HANDLE fldHnd, int offs); + +void emitIns_C_R(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fldHnd, regNumber reg, int offs); + +void emitIns_C_I(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fdlHnd, int offs, int val); + +void emitIns_IJ(emitAttr attr, regNumber reg, unsigned base); + +void emitIns_J_S(instruction ins, emitAttr attr, BasicBlock* dst, int varx, int offs); + +void emitIns_R_L(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg); + +void emitIns_R_D(instruction ins, emitAttr attr, unsigned offs, regNumber reg); + +void emitIns_I_AR( + instruction ins, emitAttr attr, int val, regNumber reg, int offs, int memCookie = 0, void* clsCookie = nullptr); + +void emitIns_I_AI(instruction ins, emitAttr attr, int val, ssize_t disp); + +void emitIns_R_AR(instruction ins, + emitAttr attr, + regNumber ireg, + regNumber reg, + int offs, + int memCookie = 0, + void* clsCookie = nullptr); + +void emitIns_R_AI(instruction ins, emitAttr attr, regNumber ireg, ssize_t disp); + +void emitIns_AR_R(instruction ins, + emitAttr attr, + regNumber ireg, + regNumber reg, + int offs, + int memCookie = 0, + void* clsCookie = nullptr); + +void emitIns_AI_R(instruction ins, emitAttr attr, regNumber ireg, ssize_t disp); + +void emitIns_I_ARR(instruction ins, emitAttr attr, int val, regNumber reg, regNumber rg2, int disp); + +void emitIns_R_ARR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, int disp); + +void emitIns_ARR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, int disp); + +void emitIns_I_ARX(instruction ins, emitAttr attr, int val, regNumber reg, regNumber rg2, unsigned mul, int disp); + +void emitIns_R_ARX( + instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, unsigned mul, int disp); + +void emitIns_ARX_R( + instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, unsigned mul, int disp); + +void emitIns_I_AX(instruction ins, emitAttr attr, int val, regNumber reg, unsigned mul, int disp); + +void emitIns_R_AX(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, unsigned mul, int disp); + +void emitIns_AX_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, unsigned mul, int disp); + +#if FEATURE_STACK_FP_X87 +void emitIns_F_F0(instruction ins, unsigned fpreg); + +void emitIns_F0_F(instruction ins, unsigned fpreg); +#endif // FEATURE_STACK_FP_X87 + +enum EmitCallType +{ + EC_FUNC_TOKEN, // Direct call to a helper/static/nonvirtual/global method + EC_FUNC_TOKEN_INDIR, // Indirect call to a helper/static/nonvirtual/global method + EC_FUNC_ADDR, // Direct call to an absolute address + + EC_FUNC_VIRTUAL, // Call to a virtual method (using the vtable) + EC_INDIR_R, // Indirect call via register + EC_INDIR_SR, // Indirect call via stack-reference (local var) + EC_INDIR_C, // Indirect call via static class var + EC_INDIR_ARD, // Indirect call via an addressing mode + + EC_COUNT +}; + +void emitIns_Call(EmitCallType callType, + CORINFO_METHOD_HANDLE methHnd, + CORINFO_SIG_INFO* sigInfo, // used to report call sites to the EE + void* addr, + ssize_t argSize, + emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize), + VARSET_VALARG_TP ptrVars, + regMaskTP gcrefRegs, + regMaskTP byrefRegs, + GenTreeIndir* indir, + bool isJump = false, + bool isNoGC = false); + +void emitIns_Call(EmitCallType callType, + CORINFO_METHOD_HANDLE methHnd, + INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo) // used to report call sites to the EE + void* addr, + ssize_t argSize, + emitAttr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize), + VARSET_VALARG_TP ptrVars, + regMaskTP gcrefRegs, + regMaskTP byrefRegs, + IL_OFFSETX ilOffset = BAD_IL_OFFSET, + regNumber ireg = REG_NA, + regNumber xreg = REG_NA, + unsigned xmul = 0, + ssize_t disp = 0, + bool isJump = false, + bool isNoGC = false); + +#ifdef _TARGET_AMD64_ +// Is the last instruction emitted a call instruction? +bool emitIsLastInsCall(); + +// Insert a NOP at the end of the the current instruction group if the last emitted instruction was a 'call', +// because the next instruction group will be an epilog. +void emitOutputPreEpilogNOP(); +#endif // _TARGET_AMD64_ + +/***************************************************************************** + * + * Given a jump, return true if it's a conditional jump. + */ + +inline bool emitIsCondJump(instrDesc* jmp) +{ + instruction ins = jmp->idIns(); + + assert(jmp->idInsFmt() == IF_LABEL); + + return (ins != INS_call && ins != INS_jmp); +} + +/***************************************************************************** + * + * Given a jump, return true if it's an unconditional jump. + */ + +inline bool emitIsUncondJump(instrDesc* jmp) +{ + instruction ins = jmp->idIns(); + + assert(jmp->idInsFmt() == IF_LABEL); + + return (ins == INS_jmp); +} + +#endif // _TARGET_XARCH_ |