未验证 提交 7df92fd4 编写于 作者: T Tanner Gooding 提交者: GitHub

Do byref liveness updates for same register GPR moves (#53684)

* Do byref liveness updates for same register GPR moves on x86/x64

* Change where emitLastEmittedIns is tracked

* Ensure emitLastEmittedIns isn't tracked across instruction groups
上级 36a7e76f
......@@ -417,6 +417,8 @@ void emitterStats(FILE* fout)
#endif // TARGET_ARM
fprintf(fout, "Total instrDescAlign: %8u (%5.2f%%)\n", emitter::emitTotalDescAlignCnt,
100.0 * emitter::emitTotalDescAlignCnt / emitter::emitTotalInsCnt);
fprintf(fout, "Total instrDescZeroSz: %8u (%5.2f%%)\n", emitter::emitTotalDescZeroSzCnt,
100.0 * emitter::emitTotalDescZeroSzCnt / emitter::emitTotalInsCnt);
fprintf(fout, "\n");
}
......@@ -665,6 +667,10 @@ void emitter::emitGenIG(insGroup* ig)
emitCurIGinsCnt = 0;
emitCurIGsize = 0;
#if defined(DEBUG)
emitCurIGZeroSzCnt = 0;
#endif // DEBUG
assert(emitCurIGjmpList == nullptr);
#if FEATURE_LOOP_ALIGN
......@@ -793,14 +799,21 @@ insGroup* emitter::emitSavIG(bool emitAdd)
emitCurCodeOffset += emitCurIGsize;
assert(IsCodeAligned(emitCurCodeOffset));
#if defined(DEBUG) || EMITTER_STATS
noway_assert((BYTE)emitCurIGZeroSzCnt == emitCurIGZeroSzCnt);
ig->igZeroSzCnt = (BYTE)emitCurIGZeroSzCnt;
#endif // DEBUG || EMITTER_STATS
#if EMITTER_STATS
emitTotalIGicnt += emitCurIGinsCnt;
emitTotalIGZeroSzCnt += emitCurIGZeroSzCnt;
emitTotalIGsize += sz;
emitSizeMethod += sz;
if (emitIGisInProlog(ig))
{
emitCurPrologInsCnt += emitCurIGinsCnt;
emitCurPrologZeroSzCnt += emitCurIGZeroSzCnt;
emitCurPrologIGSize += sz;
// Keep track of the maximums.
......@@ -993,6 +1006,16 @@ insGroup* emitter::emitSavIG(bool emitAdd)
assert(emitCurIGfreeBase <= (BYTE*)emitLastIns);
assert((BYTE*)emitLastIns < emitCurIGfreeBase + sz);
emitLastIns = (instrDesc*)((BYTE*)id + ((BYTE*)emitLastIns - (BYTE*)emitCurIGfreeBase));
if (emitLastEmittedIns != nullptr)
{
// Unlike with emitLastIns, we might be null if the group only contains
// elided instructions, in which case we'll only update in that scenario
assert(emitCurIGfreeBase <= (BYTE*)emitLastEmittedIns);
assert((BYTE*)emitLastEmittedIns < emitCurIGfreeBase + sz);
emitLastEmittedIns = (instrDesc*)((BYTE*)id + ((BYTE*)emitLastEmittedIns - (BYTE*)emitCurIGfreeBase));
}
}
// Reset the buffer free pointers
......@@ -1138,7 +1161,8 @@ void emitter::emitBegFN(bool hasFramePtr
emitPrologIG = emitIGlist = emitIGlast = emitCurIG = ig = emitAllocIG();
emitLastIns = nullptr;
emitLastIns = nullptr;
emitLastEmittedIns = nullptr;
ig->igNext = nullptr;
......@@ -1197,6 +1221,15 @@ int emitter::instrDesc::idAddrUnion::iiaGetJitDataOffset() const
//
float emitter::insEvaluateExecutionCost(instrDesc* id)
{
if (id->idIns() == INS_mov_eliminated)
{
// Elideable moves are specified to have a zero size, but are carried
// in emit so we can still do the relevant byref liveness update
assert(id->idGCref() == GCT_BYREF);
return 0;
}
insExecutionCharacteristics result = getInsExecutionCharacteristics(id);
float throughput = result.insThroughput;
float latency = result.insLatency;
......@@ -1296,13 +1329,49 @@ void emitter::dispIns(instrDesc* id)
assert(id->idDebugOnlyInfo()->idSize == sz);
#endif // DEBUG
#if defined(DEBUG) || EMITTER_STATS
if (id->idCodeSize() == 0)
{
emitCurIGZeroSzCnt++;
#if EMITTER_STATS
emitTotalDescZeroSzCnt++
#endif // EMITTER_STATS
}
#endif // DEBUG || EMITTER_STATS
#if EMITTER_STATS
emitIFcounts[id->idInsFmt()]++;
#endif
#endif // EMITTER_STATS
}
void emitter::appendToCurIG(instrDesc* id)
{
assert(id == emitLastIns);
if (emitLastIns->idIns() != INS_mov_eliminated)
{
// emitAllocAnyInstr sets emitLastIns and id
// to be the same. However, for the purposes
// of looking back we only want to consider
// certain "non-zero" size instructions and
// so we'll update the last emitted instruction
// when appending to the current IG.
emitLastEmittedIns = emitLastIns;
}
else if (emitCurIGsize == 0)
{
// If we are part of a new instruction group
// then we need to null out the last instruction
// so that we aren't incorrectly tracking across
// block boundaries.
// TOOD-CQ: We should also be able to track across
// extended instruction groups to allow more opts
emitLastEmittedIns = nullptr;
}
emitCurIGsize += id->idCodeSize();
}
......@@ -1416,7 +1485,7 @@ void* emitter::emitAllocAnyInstr(size_t sz, emitAttr opsz)
#error "Undefined target for pseudorandom NOP insertion"
#endif
emitCurIGsize += nopSize;
appendToCurIG(emitCurIGsize);
emitNextNop = emitNextRandomNop();
}
else
......@@ -4252,15 +4321,15 @@ AGAIN:
#ifdef TARGET_XARCH
/* Done if this is not a variable-sized jump */
if ((jmp->idIns() == INS_push) || (jmp->idIns() == INS_mov) || (jmp->idIns() == INS_call) ||
(jmp->idIns() == INS_push_hide))
if ((jmp->idIns() == INS_push) || (jmp->idIns() == INS_mov) || (jmp->idIns() == INS_mov_eliminated) ||
(jmp->idIns() == INS_call) || (jmp->idIns() == INS_push_hide))
{
continue;
}
#endif
#ifdef TARGET_ARM
if ((jmp->idIns() == INS_push) || (jmp->idIns() == INS_mov) || (jmp->idIns() == INS_movt) ||
(jmp->idIns() == INS_movw))
if ((jmp->idIns() == INS_push) || (jmp->idIns() == INS_mov) || (jmp->idIns() == INS_mov_eliminated) ||
(jmp->idIns() == INS_movt) || (jmp->idIns() == INS_movw))
{
continue;
}
......@@ -5974,6 +6043,9 @@ unsigned emitter::emitEndCodeGen(Compiler* comp,
printf("\t\t\t\t\t\t;; bbWeight=%s PerfScore %.2f", refCntWtd2str(ig->igWeight), ig->igPerfScore);
}
*instrCount += ig->igInsCnt;
// We don't want to include zero size instructions in the count, as they aren't impactful
*instrCount -= ig->igZeroSzCnt;
#endif // DEBUG
emitCurIG = nullptr;
......
......@@ -299,7 +299,11 @@ struct insGroup
unsigned igStkLvl; // stack level on entry
#endif
regMaskSmall igGCregs; // set of registers with live GC refs
unsigned char igInsCnt; // # of instructions in this group
unsigned char igInsCnt; // # of instructions in this group
#if defined(DEBUG)
unsigned char igZeroSzCnt; // # of zero size instructions in this group
#endif // DEBUG
#else // REGMASK_BITS
......@@ -314,7 +318,11 @@ struct insGroup
unsigned igStkLvl; // stack level on entry
#endif
unsigned char igInsCnt; // # of instructions in this group
unsigned char igInsCnt; // # of instructions in this group
#if defined(DEBUG)
unsigned char igZeroSzCnt; // # of zero size instructions in this group
#endif // DEBUG
#endif // REGMASK_BITS
......@@ -920,7 +928,7 @@ protected:
break;
}
return size;
return (idIns() != INS_mov_eliminated) ? size : 0;
}
#elif defined(TARGET_ARM)
......@@ -932,7 +940,7 @@ protected:
unsigned idCodeSize() const
{
unsigned result = (_idInsSize == ISZ_16BIT) ? 2 : (_idInsSize == ISZ_32BIT) ? 4 : 6;
return result;
return (idIns() != INS_mov_eliminated) ? result : 0;
}
insSize idInsSize() const
{
......@@ -1793,6 +1801,10 @@ private:
UNATIVE_OFFSET emitCurCodeOffset; // current code offset within group
UNATIVE_OFFSET emitTotalCodeSize; // bytes of code in entire method
#if defined(DEBUG) || EMITTER_STATS
unsigned emitCurIGZeroSzCnt; // # of zero size instr's in buffer
#endif // DEBUG || EMITTER_STATS
insGroup* emitFirstColdIG; // first cold instruction group
void emitSetFirstColdIGCookie(void* bbEmitCookie)
......@@ -1889,6 +1901,7 @@ private:
}
instrDesc* emitLastIns;
instrDesc* emitLastEmittedIns;
#ifdef DEBUG
void emitCheckIGoffsets();
......@@ -2317,14 +2330,16 @@ public:
static unsigned emitTotalInsCnt;
static unsigned emitCurPrologInsCnt; // current number of prolog instrDescs
static size_t emitCurPrologIGSize; // current size of prolog instrDescs
static unsigned emitMaxPrologInsCnt; // maximum number of prolog instrDescs
static size_t emitMaxPrologIGSize; // maximum size of prolog instrDescs
static unsigned emitCurPrologInsCnt; // current number of prolog instrDescs
static unsigned emitCurPrologZeroSzCnt; // current number of elided prolog instrDescs
static size_t emitCurPrologIGSize; // current size of prolog instrDescs
static unsigned emitMaxPrologInsCnt; // maximum number of prolog instrDescs
static size_t emitMaxPrologIGSize; // maximum size of prolog instrDescs
static unsigned emitTotalIGcnt; // total number of insGroup allocated
static unsigned emitTotalPhIGcnt; // total number of insPlaceholderGroupData allocated
static unsigned emitTotalIGicnt;
static unsigned emitTotalIGZeroSzCnt;
static size_t emitTotalIGsize;
static unsigned emitTotalIGmcnt; // total method count
static unsigned emitTotalIGExtend; // total number of 'emitExtend' (typically overflow) groups
......@@ -2359,6 +2374,7 @@ public:
static unsigned emitSmallCns[SMALL_CNS_TSZ];
static unsigned emitLargeCnsCnt;
static unsigned emitTotalDescAlignCnt;
static unsigned emitTotalDescZeroSzCnt;
static unsigned emitIFcounts[IF_COUNT];
......
......@@ -1230,6 +1230,7 @@ bool emitter::IsMovInstruction(instruction ins)
switch (ins)
{
case INS_mov:
case INS_mov_eliminated:
case INS_sxtb:
case INS_sxth:
case INS_uxtb:
......@@ -2065,8 +2066,15 @@ void emitter::emitIns_Mov(instruction ins,
{
if (canSkip && (dstReg == srcReg))
{
// These instructions have no side effect and can be skipped
return;
// These instructions might have a side effect in the form of a
// byref liveness update, so preserve them but emit nothing
if (!EA_IS_BYREF(attr))
{
return;
}
ins = INS_mov_eliminated;
}
fmt = IF_T1_D0;
sf = INS_FLAGS_NOT_SET;
......@@ -5767,6 +5775,18 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
VARSET_TP GCvars(VarSetOps::UninitVal());
if (ins == INS_mov_eliminated)
{
// Elideable moves are specified to have a zero size, but are carried
// in emit so we can still do the relevant byref liveness update
assert(id->idGCref() == GCT_BYREF);
assert(id->idCodeSize() == 0);
sz = SMALL_IDSC_SIZE;
goto UPDATE_LIVENESS;
}
/* What instruction format have we got? */
switch (fmt)
......@@ -6587,6 +6607,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
break;
}
UPDATE_LIVENESS:
// Determine if any registers now hold GC refs, or whether a register that was overwritten held a GC ref.
// We assume here that "id->idGCref()" is not GC_NONE only if the instruction described by "id" writes a
// GC ref to register "id->idReg1()". (It may, apparently, also not be GC_NONE in other cases, such as
......@@ -6703,9 +6724,9 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
}
#endif
/* All instructions are expected to generate code */
/* All instructions, except eliminated moves, are expected to generate code */
assert(*dp != dst);
assert((*dp != dst) || (ins == INS_mov_eliminated));
*dp = dst;
......@@ -7101,6 +7122,17 @@ void emitter::emitDispInsHex(instrDesc* id, BYTE* code, size_t sz)
void emitter::emitDispInsHelp(
instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* code, size_t sz, insGroup* ig)
{
if (id->idIns() == INS_mov_eliminated)
{
// Elideable moves are specified to have a zero size, but are carried
// in emit so we can still do the relevant byref liveness update
assert(id->idGCref() == GCT_BYREF);
assert(id->idCodeSize() == 0);
return;
}
if (EMITVERBOSE)
{
unsigned idNum = id->idDebugOnlyInfo()->idNum; // Do not remove this! It is needed for VisualStudio
......
......@@ -4088,7 +4088,9 @@ void emitter::emitIns_Mov(
if (IsRedundantMov(ins, size, dstReg, srcReg, canSkip))
{
// These instructions have no side effect and can be skipped
// TODO-ARM64: These instructions might have a side effect in the form of a
// byref liveness update, so we should preserve them but emit nothing
return;
}
......@@ -4104,13 +4106,10 @@ void emitter::emitIns_Mov(
return emitIns_R_R_I(INS_mov, size, dstReg, srcReg, 0);
}
}
else
else if (isVectorRegister(srcReg))
{
if (isVectorRegister(srcReg))
{
assert(isGeneralRegister(dstReg));
return emitIns_R_R_I(INS_mov, size, dstReg, srcReg, 0);
}
assert(isGeneralRegister(dstReg));
return emitIns_R_R_I(INS_mov, size, dstReg, srcReg, 0);
}
// Is this a MOV to/from SP instruction?
......@@ -10348,6 +10347,17 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
assert(REG_NA == (int)REG_NA);
if (ins == INS_mov_eliminated)
{
// Elideable moves are specified to have a zero size, but are carried
// in emit so we can still do the relevant byref liveness update
assert(id->idGCref() == GCT_BYREF);
assert(id->idCodeSize() == 0);
goto UPDATE_LIVENESS;
}
/* What instruction format have we got? */
switch (fmt)
......@@ -11461,6 +11471,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
break;
}
UPDATE_LIVENESS:
// Determine if any registers now hold GC refs, or whether a register that was overwritten held a GC ref.
// We assume here that "id->idGCref()" is not GC_NONE only if the instruction described by "id" writes a
// GC ref to register "id->idReg1()". (It may, apparently, also not be GC_NONE in other cases, such as
......@@ -11576,9 +11587,9 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
}
#endif
/* All instructions are expected to generate code */
/* All instructions, except eliminated moves, are expected to generate code */
assert(*dp != dst);
assert((*dp != dst) || (ins == INS_mov_eliminated));
*dp = dst;
......@@ -12188,6 +12199,17 @@ void emitter::emitDispInsHex(instrDesc* id, BYTE* code, size_t sz)
void emitter::emitDispIns(
instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig)
{
if (id->idIns() == INS_mov_eliminated)
{
// Elideable moves are specified to have a zero size, but are carried
// in emit so we can still do the relevant byref liveness update
assert(id->idGCref() == GCT_BYREF);
assert(id->idCodeSize() == 0);
return;
}
if (EMITVERBOSE)
{
unsigned idNum =
......@@ -15535,6 +15557,7 @@ bool emitter::IsMovInstruction(instruction ins)
{
case INS_fmov:
case INS_mov:
case INS_mov_eliminated:
case INS_sxtb:
case INS_sxth:
case INS_sxtw:
......@@ -15617,23 +15640,24 @@ bool emitter::IsRedundantMov(instruction ins, emitAttr size, regNumber dst, regN
bool isFirstInstrInBlock = (emitCurIGinsCnt == 0) && ((emitCurIG->igFlags & IGF_EXTEND) == 0);
if (!isFirstInstrInBlock && // Don't optimize if instruction is not the first instruction in IG.
(emitLastIns != nullptr) &&
(emitLastIns->idIns() == INS_mov) && // Don't optimize if last instruction was not 'mov'.
(emitLastIns->idOpSize() == size)) // Don't optimize if operand size is different than previous instruction.
(emitLastEmittedIns != nullptr) &&
(emitLastEmittedIns->idIns() == INS_mov) && // Don't optimize if last instruction was not 'mov'.
(emitLastEmittedIns->idOpSize() == size)) // Don't optimize if operand size is different than previous
// instruction.
{
// Check if we did same move in prev instruction except dst/src were switched.
regNumber prevDst = emitLastIns->idReg1();
regNumber prevSrc = emitLastIns->idReg2();
insFormat lastInsfmt = emitLastIns->idInsFmt();
regNumber prevDst = emitLastEmittedIns->idReg1();
regNumber prevSrc = emitLastEmittedIns->idReg2();
insFormat lastInsfmt = emitLastEmittedIns->idInsFmt();
if ((prevDst == dst) && (prevSrc == src))
{
assert(emitLastIns->idOpSize() == size);
assert(emitLastEmittedIns->idOpSize() == size);
JITDUMP("\n -- suppressing mov because previous instruction already moved from src to dst register.\n");
return true;
}
// Sometimes emitLastIns can be a mov with single register e.g. "mov reg, #imm". So ensure to
// Sometimes emitLastEmittedIns can be a mov with single register e.g. "mov reg, #imm". So ensure to
// optimize formats that does vector-to-vector or scalar-to-scalar register movs.
bool isValidLastInsFormats = ((lastInsfmt == IF_DV_3C) || (lastInsfmt == IF_DR_2G) || (lastInsfmt == IF_DR_2E));
......@@ -15696,16 +15720,17 @@ bool emitter::IsRedundantLdStr(
{
bool isFirstInstrInBlock = (emitCurIGinsCnt == 0) && ((emitCurIG->igFlags & IGF_EXTEND) == 0);
if (((ins != INS_ldr) && (ins != INS_str)) || (isFirstInstrInBlock) || (emitLastIns == nullptr))
if (((ins != INS_ldr) && (ins != INS_str)) || (isFirstInstrInBlock) || (emitLastEmittedIns == nullptr))
{
return false;
}
regNumber prevReg1 = emitLastIns->idReg1();
regNumber prevReg2 = emitLastIns->idReg2();
insFormat lastInsfmt = emitLastIns->idInsFmt();
emitAttr prevSize = emitLastIns->idOpSize();
ssize_t prevImm = emitLastIns->idIsLargeCns() ? ((instrDescCns*)emitLastIns)->idcCnsVal : emitLastIns->idSmallCns();
regNumber prevReg1 = emitLastEmittedIns->idReg1();
regNumber prevReg2 = emitLastEmittedIns->idReg2();
insFormat lastInsfmt = emitLastEmittedIns->idInsFmt();
emitAttr prevSize = emitLastEmittedIns->idOpSize();
ssize_t prevImm = emitLastEmittedIns->idIsLargeCns() ? ((instrDescCns*)emitLastEmittedIns)->idcCnsVal
: emitLastEmittedIns->idSmallCns();
// Only optimize if:
// 1. "base" or "base plus immediate offset" addressing modes.
......@@ -15716,7 +15741,7 @@ bool emitter::IsRedundantLdStr(
return false;
}
if ((ins == INS_ldr) && (emitLastIns->idIns() == INS_str))
if ((ins == INS_ldr) && (emitLastEmittedIns->idIns() == INS_str))
{
// If reg1 is of size less than 8-bytes, then eliminating the 'ldr'
// will not zero the upper bits of reg1.
......@@ -15737,7 +15762,7 @@ bool emitter::IsRedundantLdStr(
return true;
}
}
else if ((ins == INS_str) && (emitLastIns->idIns() == INS_ldr))
else if ((ins == INS_str) && (emitLastEmittedIns->idIns() == INS_ldr))
{
// Make sure src and dst registers are not same.
// ldr x0, [x0, #4]
......
此差异已折叠。
......@@ -146,20 +146,21 @@ INST6(ldrsh, "ldrsh", 0,LD, IF_EN6A, 0x5E00, BAD_CODE, 0xF9300000,
// ldrsh Rt,[Rn+i12] T2_K1 111110011011nnnn ttttiiiiiiiiiiii F9B0 0000 imm(0-4095)
// ldrsh Rt,[PC+i12] T2_K4 11111001U0111111 ttttiiiiiiiiiiii F93F 0000 imm(+-4095)
// enum name FP LD/ST Rd, Rm Rd,Rm Rd,i8 Rd,+i8<<i4 S / Rn,Rm{,sh}
// T1_E T1_D0 T1_J0 T2_L1/L2 T2_C3/C8
INST5(mov, "mov", 0, 0, IF_EN5A, 0x0000, 0x4600, 0x2000, 0xF04F0000, 0xEA5F0000)
// movs Rd,Rm T1_E 0000000000mmmddd 0000 low
// mov Rd,Rm T1_D0 01000110Dmmmmddd 4600 high
// movs Rd,i8 T1_J0 00100dddiiiiiiii 2000 low imm(0-255)
// mov{s} Rd,+i8<<i4 T2_L1 11110i00010S1111 0iiiddddiiiiiiii F04F 0000 imm(i8<<i4)
// mov{s} Rd,Rm T2_C3 1110101001011111 0000dddd0000mmmm EA5F 0000
INST5(cmp, "cmp", 0,CMP,IF_EN5B, 0x4280, 0x4500, 0x2800, 0xF1B00F00, 0xEBB00F00)
// cmp Rn,Rm T1_E 0100001010mmmnnn 4280 low
// cmp Rn,Rm T1_D0 01000101Nmmmmnnn 4500 high
// cmp Rn,i8 T1_J0 00101nnniiiiiiii 2800 low imm(0-255)
// cmp Rn,+i8<<i4 T2_L2 11110i011011nnnn 0iii1111iiiiiiii F1B0 0F00 imm(i8<<i4)
// cmp Rn,Rm{,sh} T2_C8 111010111011nnnn 0iii1111iishmmmm EBB0 0F00
// enum name FP LD/ST Rd, Rm Rd,Rm Rd,i8 Rd,+i8<<i4 S / Rn,Rm{,sh}
// T1_E T1_D0 T1_J0 T2_L1/L2 T2_C3/C8
INST5(mov, "mov", 0, 0, IF_EN5A, 0x0000, 0x4600, 0x2000, 0xF04F0000, 0xEA5F0000)
// movs Rd,Rm T1_E 0000000000mmmddd 0000 low
// mov Rd,Rm T1_D0 01000110Dmmmmddd 4600 high
// movs Rd,i8 T1_J0 00100dddiiiiiiii 2000 low imm(0-255)
// mov{s} Rd,+i8<<i4 T2_L1 11110i00010S1111 0iiiddddiiiiiiii F04F 0000 imm(i8<<i4)
// mov{s} Rd,Rm T2_C3 1110101001011111 0000dddd0000mmmm EA5F 0000
INST5(mov_eliminated, "mov_eliminated", 0, 0, IF_EN5A, 0x0000, 0x4600, 0x2000, 0xF04F0000, 0xEA5F0000)
INST5(cmp, "cmp", 0,CMP,IF_EN5B, 0x4280, 0x4500, 0x2800, 0xF1B00F00, 0xEBB00F00)
// cmp Rn,Rm T1_E 0100001010mmmnnn 4280 low
// cmp Rn,Rm T1_D0 01000101Nmmmmnnn 4500 high
// cmp Rn,i8 T1_J0 00101nnniiiiiiii 2800 low imm(0-255)
// cmp Rn,+i8<<i4 T2_L2 11110i011011nnnn 0iii1111iiiiiiii F1B0 0F00 imm(i8<<i4)
// cmp Rn,Rm{,sh} T2_C8 111010111011nnnn 0iii1111iishmmmm EBB0 0F00
// enum name FP LD/ST Rdn, Rn Rd,Rn,i5 Rd,Rn,Rm Rd,Rn,i5
// T1_E T2_C T2_C4 T2_C2
......
......@@ -58,17 +58,18 @@
// clang-format off
INST9(invalid, "INVALID", 0, IF_NONE, BAD_CODE, BAD_CODE, BAD_CODE, BAD_CODE, BAD_CODE, BAD_CODE, BAD_CODE, BAD_CODE, BAD_CODE)
// enum name info DR_2E DR_2G DI_1B DI_1D DV_3C DV_2B DV_2C DV_2E DV_2F
INST9(mov, "mov", 0, IF_EN9, 0x2A0003E0, 0x11000000, 0x52800000, 0x320003E0, 0x0EA01C00, 0x0E003C00, 0x4E001C00, 0x5E000400, 0x6E000400)
// mov Rd,Rm DR_2E X0101010000mmmmm 00000011111ddddd 2A00 03E0
// mov Rd,Rn DR_2G X001000100000000 000000nnnnnddddd 1100 0000 mov to/from SP only
// mov Rd,imm(i16,hw) DI_1B X10100101hwiiiii iiiiiiiiiiiddddd 5280 0000 imm(i16,hw)
// mov Rd,imm(N,r,s) DI_1D X01100100Nrrrrrr ssssss11111ddddd 3200 03E0 imm(N,r,s)
// mov Vd,Vn DV_3C 0Q001110101nnnnn 000111nnnnnddddd 0EA0 1C00 Vd,Vn
// mov Rd,Vn[0] DV_2B 0Q001110000iiiii 001111nnnnnddddd 0E00 3C00 Rd,Vn[] (to general)
// mov Vd[],Rn DV_2C 01001110000iiiii 000111nnnnnddddd 4E00 1C00 Vd[],Rn (from general)
// mov Vd,Vn[] DV_2E 01011110000iiiii 000001nnnnnddddd 5E00 0400 Vd,Vn[] (scalar by element)
// mov Vd[],Vn[] DV_2F 01101110000iiiii 0jjjj1nnnnnddddd 6E00 0400 Vd[],Vn[] (from/to elem)
// enum name info DR_2E DR_2G DI_1B DI_1D DV_3C DV_2B DV_2C DV_2E DV_2F
INST9(mov, "mov", 0, IF_EN9, 0x2A0003E0, 0x11000000, 0x52800000, 0x320003E0, 0x0EA01C00, 0x0E003C00, 0x4E001C00, 0x5E000400, 0x6E000400)
// mov Rd,Rm DR_2E X0101010000mmmmm 00000011111ddddd 2A00 03E0
// mov Rd,Rn DR_2G X001000100000000 000000nnnnnddddd 1100 0000 mov to/from SP only
// mov Rd,imm(i16,hw) DI_1B X10100101hwiiiii iiiiiiiiiiiddddd 5280 0000 imm(i16,hw)
// mov Rd,imm(N,r,s) DI_1D X01100100Nrrrrrr ssssss11111ddddd 3200 03E0 imm(N,r,s)
// mov Vd,Vn DV_3C 0Q001110101nnnnn 000111nnnnnddddd 0EA0 1C00 Vd,Vn
// mov Rd,Vn[0] DV_2B 0Q001110000iiiii 001111nnnnnddddd 0E00 3C00 Rd,Vn[] (to general)
// mov Vd[],Rn DV_2C 01001110000iiiii 000111nnnnnddddd 4E00 1C00 Vd[],Rn (from general)
// mov Vd,Vn[] DV_2E 01011110000iiiii 000001nnnnnddddd 5E00 0400 Vd,Vn[] (scalar by element)
// mov Vd[],Vn[] DV_2F 01101110000iiiii 0jjjj1nnnnnddddd 6E00 0400 Vd[],Vn[] (from/to elem)
INST9(mov_eliminated, "mov_eliminated", 0, IF_EN9, 0x2A0003E0, 0x11000000, 0x52800000, 0x320003E0, 0x0EA01C00, 0x0E003C00, 0x4E001C00, 0x5E000400, 0x6E000400)
// enum name info DR_3A DR_3B DR_3C DI_2A DV_3A DV_3E
INST6(add, "add", 0, IF_EN6A, 0x0B000000, 0x0B000000, 0x0B200000, 0x11000000, 0x0E208400, 0x5EE08400)
......
......@@ -79,6 +79,7 @@ INST4(xor, "xor", IUM_RW, 0x000030, 0x003080,
INST4(cmp, "cmp", IUM_RD, 0x000038, 0x003880, 0x00003A, 0x00003C, Writes_OF | Writes_SF | Writes_ZF | Writes_AF | Writes_PF | Writes_CF )
INST4(test, "test", IUM_RD, 0x000084, 0x0000F6, 0x000084, 0x0000A8, Resets_OF | Writes_SF | Writes_ZF | Undefined_AF | Writes_PF | Resets_CF )
INST4(mov, "mov", IUM_WR, 0x000088, 0x0000C6, 0x00008A, 0x0000B0, INS_FLAGS_None )
INST4(mov_eliminated, "mov_eliminated", IUM_WR, 0x000088, 0x0000C6, 0x00008A, 0x0000B0, INS_FLAGS_None)
INST4(lea, "lea", IUM_WR, BAD_CODE, BAD_CODE, 0x00008D, BAD_CODE, INS_FLAGS_None )
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册