// 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 */ /************************************************************************/ // code_t is a type used to accumulate bits of opcode + prefixes. On amd64, it must be 64 bits // to support the REX prefixes. On both x86 and amd64, it must be 64 bits to support AVX, with // its 3-byte VEX prefix. typedef unsigned __int64 code_t; struct CnsVal { ssize_t cnsVal; bool cnsReloc; }; UNATIVE_OFFSET emitInsSize(code_t code); UNATIVE_OFFSET emitInsSizeSV(code_t code, int var, int dsp); UNATIVE_OFFSET emitInsSizeSV(instrDesc* id, code_t code, int var, int dsp); UNATIVE_OFFSET emitInsSizeSV(instrDesc* id, code_t code, int var, int dsp, int val); UNATIVE_OFFSET emitInsSizeRR(instrDesc* id, code_t code); UNATIVE_OFFSET emitInsSizeRR(instrDesc* id, code_t code, int val); UNATIVE_OFFSET emitInsSizeRR(instruction ins, regNumber reg1, regNumber reg2, emitAttr attr); UNATIVE_OFFSET emitInsSizeAM(instrDesc* id, code_t code); UNATIVE_OFFSET emitInsSizeAM(instrDesc* id, code_t code, int val); UNATIVE_OFFSET emitInsSizeCV(instrDesc* id, code_t code); UNATIVE_OFFSET emitInsSizeCV(instrDesc* id, code_t code, int val); BYTE* emitOutputAM(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc = nullptr); BYTE* emitOutputSV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc = nullptr); BYTE* emitOutputCV(BYTE* dst, instrDesc* id, code_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); BYTE* emitOutputRRR(BYTE* dst, instrDesc* id); BYTE* emitOutputLJ(BYTE* dst, instrDesc* id); unsigned emitOutputRexOrVexPrefixIfNeeded(instruction ins, BYTE* dst, code_t& code); unsigned emitGetRexPrefixSize(instruction ins); unsigned emitGetVexPrefixSize(instruction ins, emitAttr attr); unsigned emitGetPrefixSize(code_t code); unsigned emitGetAdjustedSize(instruction ins, emitAttr attr, code_t code); unsigned insEncodeReg012(instruction ins, regNumber reg, emitAttr size, code_t* code); unsigned insEncodeReg345(instruction ins, regNumber reg, emitAttr size, code_t* code); code_t insEncodeReg3456(instruction ins, regNumber reg, emitAttr size, code_t code); unsigned insEncodeRegSIB(instruction ins, regNumber reg, code_t* code); code_t insEncodeMRreg(instruction ins, code_t code); code_t insEncodeRMreg(instruction ins, code_t code); code_t insEncodeMRreg(instruction ins, regNumber reg, emitAttr size, code_t code); code_t insEncodeRRIb(instruction ins, regNumber reg, emitAttr size); code_t insEncodeOpreg(instruction ins, regNumber reg, emitAttr size); unsigned insSSval(unsigned scale); bool IsAVXInstruction(instruction ins); code_t insEncodeMIreg(instruction ins, regNumber reg, emitAttr size, code_t code); code_t AddRexWPrefix(instruction ins, code_t code); code_t AddRexRPrefix(instruction ins, code_t code); code_t AddRexXPrefix(instruction ins, code_t code); code_t AddRexBPrefix(instruction ins, code_t code); code_t AddRexPrefix(instruction ins, code_t code); bool EncodedBySSE38orSSE3A(instruction ins); bool Is4ByteSSEInstruction(instruction ins); bool AreUpper32BitsZero(regNumber reg); bool hasRexPrefix(code_t code) { #ifdef _TARGET_AMD64_ const code_t REX_PREFIX_MASK = 0xFF00000000LL; return (code & REX_PREFIX_MASK) != 0; #else // !_TARGET_AMD64_ return false; #endif // !_TARGET_AMD64_ } // 3-byte VEX prefix starts with byte 0xC4 #define VEX_PREFIX_MASK_3BYTE 0xFF000000000000ULL #define VEX_PREFIX_CODE_3BYTE 0xC4000000000000ULL bool TakesVexPrefix(instruction ins); // Returns true if the instruction encoding already contains VEX prefix bool hasVexPrefix(code_t code) { return (code & VEX_PREFIX_MASK_3BYTE) == VEX_PREFIX_CODE_3BYTE; } code_t AddVexPrefix(instruction ins, code_t code, emitAttr attr); code_t AddVexPrefixIfNeeded(instruction ins, code_t code, emitAttr size) { if (TakesVexPrefix(ins)) { code = AddVexPrefix(ins, code, size); } return code; } code_t AddVexPrefixIfNeededAndNotPresent(instruction ins, code_t code, emitAttr size) { if (TakesVexPrefix(ins) && !hasVexPrefix(code)) { code = AddVexPrefix(ins, code, size); } return code; } bool useVEXEncodings; bool UseVEXEncoding() { return useVEXEncodings; } void SetUseVEXEncoding(bool value) { useVEXEncodings = value; } bool containsAVXInstruction = false; bool ContainsAVX() { return containsAVXInstruction; } void SetContainsAVX(bool value) { containsAVXInstruction = value; } bool contains256bitAVXInstruction = false; bool Contains256bitAVX() { return contains256bitAVXInstruction; } void SetContains256bitAVX(bool value) { contains256bitAVXInstruction = value; } bool IsDstDstSrcAVXInstruction(instruction ins); bool IsDstSrcSrcAVXInstruction(instruction ins); bool IsThreeOperandAVXInstruction(instruction ins) { return (IsDstDstSrcAVXInstruction(ins) || IsDstSrcSrcAVXInstruction(ins)); } bool isAvxBlendv(instruction ins) { return ins == INS_vblendvps || ins == INS_vblendvpd || ins == INS_vpblendvb; } bool isSse41Blendv(instruction ins) { return ins == INS_blendvps || ins == INS_blendvpd || ins == INS_pblendvb; } bool isPrefetch(instruction ins) { return (ins == INS_prefetcht0) || (ins == INS_prefetcht1) || (ins == INS_prefetcht2) || (ins == INS_prefetchnta); } /************************************************************************/ /* 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); #if FEATURE_FIXED_OUT_ARGS void emitAdjustStackDepthPushPop(instruction ins) { } void emitAdjustStackDepth(instruction ins, ssize_t val) { } #else // !FEATURE_FIXED_OUT_ARGS void emitAdjustStackDepthPushPop(instruction ins); void emitAdjustStackDepth(instruction ins, ssize_t val); #endif // !FEATURE_FIXED_OUT_ARGS /***************************************************************************** * * 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, GenTree* 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); void emitIns_AR(instruction ins, emitAttr attr, regNumber base, int offs); void emitIns_AR_R_R(instruction ins, emitAttr attr, regNumber op2Reg, regNumber op3Reg, regNumber base, int offs); void emitIns_R_A(instruction ins, emitAttr attr, regNumber reg1, GenTreeIndir* indir); void emitIns_R_A_I(instruction ins, emitAttr attr, regNumber reg1, GenTreeIndir* indir, int ival); void emitIns_R_AR_I(instruction ins, emitAttr attr, regNumber reg1, regNumber base, int offs, int ival); void emitIns_R_C_I(instruction ins, emitAttr attr, regNumber reg1, CORINFO_FIELD_HANDLE fldHnd, int offs, int ival); void emitIns_R_S_I(instruction ins, emitAttr attr, regNumber reg1, int varx, int offs, int ival); void emitIns_R_R_A(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, GenTreeIndir* indir); void emitIns_R_R_AR(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber base, int offs); void emitIns_R_AR_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber base, regNumber index, int scale, int offs); void emitIns_R_R_C( instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, CORINFO_FIELD_HANDLE fldHnd, int offs); void emitIns_R_R_S(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, int varx, int offs); void emitIns_R_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3); void emitIns_R_R_A_I( instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, GenTreeIndir* indir, int ival, insFormat fmt); void emitIns_R_R_AR_I( instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber base, int offs, int ival); void emitIns_S_R_I(instruction ins, emitAttr attr, int varNum, int offs, regNumber reg, int ival); void emitIns_AR_R_I(instruction ins, emitAttr attr, regNumber base, int disp, regNumber ireg, int ival); void emitIns_R_R_C_I( instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, CORINFO_FIELD_HANDLE fldHnd, int offs, int ival); void emitIns_R_R_R_I(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, int ival); void emitIns_R_R_S_I(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, int varx, int offs, int ival); void emitIns_R_R_A_R( instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op3Reg, GenTreeIndir* indir); void emitIns_R_R_AR_R( instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op3Reg, regNumber base, int offs); void emitIns_R_R_C_R(instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op3Reg, CORINFO_FIELD_HANDLE fldHnd, int offs); void emitIns_R_R_S_R( instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op3Reg, int varx, int offs); void emitIns_R_R_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, regNumber reg4); 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); 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); 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); 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); #ifdef FEATURE_HW_INTRINSICS void emitIns_SIMD_R_R_I(instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, int ival); void emitIns_SIMD_R_R_A(instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, GenTreeIndir* indir); void emitIns_SIMD_R_R_AR( instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber base, int offset); void emitIns_SIMD_R_R_C( instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, CORINFO_FIELD_HANDLE fldHnd, int offs); void emitIns_SIMD_R_R_R(instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg); void emitIns_SIMD_R_R_S(instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, int varx, int offs); void emitIns_SIMD_R_R_A_I( instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, GenTreeIndir* indir, int ival); void emitIns_SIMD_R_R_AR_I( instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber base, int ival); void emitIns_SIMD_R_R_C_I(instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, CORINFO_FIELD_HANDLE fldHnd, int offs, int ival); void emitIns_SIMD_R_R_R_I( instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, int ival); void emitIns_SIMD_R_R_S_I( instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, int varx, int offs, int ival); void emitIns_SIMD_R_R_R_A( instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, GenTreeIndir* indir); void emitIns_SIMD_R_R_R_AR( instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, regNumber base); void emitIns_SIMD_R_R_R_C(instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, CORINFO_FIELD_HANDLE fldHnd, int offs); void emitIns_SIMD_R_R_R_R( instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, regNumber op3Reg); void emitIns_SIMD_R_R_R_S( instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, int varx, int offs); void emitIns_SIMD_R_R_A_R( instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, GenTreeIndir* indir); void emitIns_SIMD_R_R_AR_R( instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, regNumber base); void emitIns_SIMD_R_R_C_R(instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, CORINFO_FIELD_HANDLE fldHnd, int offs); void emitIns_SIMD_R_R_S_R( instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, int varx, int offs); #endif // FEATURE_HW_INTRINSICS 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 }; // clang-format off 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); // clang-format on #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_