Как перестать поддерживать ее, при выполнении клиентского кода в ходе динамической трансляции.
Просто иметь оптимизации, которые знают, какой регистр какое название имеет.
Раз уж ты поставил тег .NET, то у платформы есть свой JIT компилятор, который пишется под каждую платформу (CPU) и имеет знание о ее регистрах.
Вот пример того, как это делается в исходном коде:
1. Каждая платформа регистрирует свои регистры и информацию о них.
#if defined(TARGET_XARCH)
#if defined(TARGET_X86)
/*
REGDEF(name, rnum, mask, sname) */
REGDEF(EAX, 0, 0x01, "eax" )
REGDEF(ECX, 1, 0x02, "ecx" )
REGDEF(EDX, 2, 0x04, "edx" )
REGDEF(EBX, 3, 0x08, "ebx" )
REGDEF(ESP, 4, 0x10, "esp" )
REGDEF(EBP, 5, 0x20, "ebp" )
REGDEF(ESI, 6, 0x40, "esi" )
REGDEF(EDI, 7, 0x80, "edi" )
REGALIAS(RAX, EAX)
REGALIAS(RCX, ECX)
REGALIAS(RDX, EDX)
REGALIAS(RBX, EBX)
REGALIAS(RSP, ESP)
REGALIAS(RBP, EBP)
REGALIAS(RSI, ESI)
REGALIAS(RDI, EDI)
#else // !defined(TARGET_X86)
/*
REGDEF(name, rnum, mask, sname) */
REGDEF(RAX, 0, 0x0001, "rax" )
REGDEF(RCX, 1, 0x0002, "rcx" )
REGDEF(RDX, 2, 0x0004, "rdx" )
REGDEF(RBX, 3, 0x0008, "rbx" )
REGDEF(RSP, 4, 0x0010, "rsp" )
REGDEF(RBP, 5, 0x0020, "rbp" )
REGDEF(RSI, 6, 0x0040, "rsi" )
REGDEF(RDI, 7, 0x0080, "rdi" )
REGDEF(R8, 8, 0x0100, "r8" )
REGDEF(R9, 9, 0x0200, "r9" )
REGDEF(R10, 10, 0x0400, "r10" )
REGDEF(R11, 11, 0x0800, "r11" )
REGDEF(R12, 12, 0x1000, "r12" )
REGDEF(R13, 13, 0x2000, "r13" )
REGDEF(R14, 14, 0x4000, "r14" )
REGDEF(R15, 15, 0x8000, "r15" )
REGALIAS(EAX, RAX)
REGALIAS(ECX, RCX)
REGALIAS(EDX, RDX)
REGALIAS(EBX, RBX)
REGALIAS(ESP, RSP)
REGALIAS(EBP, RBP)
REGALIAS(ESI, RSI)
REGALIAS(EDI, RDI)
#endif // !defined(TARGET_X86)
2. Для каждой платформы реализуются своя пара кодогенератор / эмиттер
// Кодогенератор
void CodeGen::genCodeForBinary(GenTreeOp* treeNode)
{
GenTree* op1 = treeNode->gtGetOp1();
GenTree* op2 = treeNode->gtGetOp2();
instruction ins = genGetInsForOper(treeNode->OperGet(), targetType);
regNumber op1reg = op1->isUsedFromReg() ? op1->GetRegNum() : REG_NA;
regNumber op2reg = op2->isUsedFromReg() ? op2->GetRegNum() : REG_NA;
GenTree* dst;
GenTree* src;
// This is the case of reg1 = reg1 op reg2
// We're ready to emit the instruction without any moves
if (op1reg == targetReg)
{
dst = op1;
src = op2;
}
// We have reg1 = reg2 op reg1
// In order for this operation to be correct
// we need that op is a commutative operation so
// we can convert it into reg1 = reg1 op reg2 and emit
// the same code as above
else if (op2reg == targetReg)
{
dst = op2;
src = op1;
}
// dest, op1 and op2 registers are different:
// reg3 = reg1 op reg2
// We can implement this by issuing a mov:
// reg3 = reg1
// reg3 = reg3 op reg2
else
{
var_types op1Type = op1->TypeGet();
inst_Mov(op1Type, targetReg, op1reg, /* canSkip */ false);
regSet.verifyRegUsed(targetReg);
gcInfo.gcMarkRegPtrVal(targetReg, op1Type);
dst = treeNode;
src = op2;
}
// try to use an inc or dec
if (oper == GT_ADD && !varTypeIsFloating(treeNode) && src->isContainedIntOrIImmed() && !treeNode->gtOverflowEx())
{
if (src->IsIntegralConst(1))
{
emit->emitIns_R(INS_inc, emitTypeSize(treeNode), targetReg);
genProduceReg(treeNode);
return;
}
else if (src->IsIntegralConst(-1))
{
emit->emitIns_R(INS_dec, emitTypeSize(treeNode), targetReg);
genProduceReg(treeNode);
return;
}
}
regNumber r = emit->emitInsBinary(ins, emitTypeSize(treeNode), dst, src);
}
// Эммитер
/*****************************************************************************
*
* Add an instruction with two register operands.
*/
void emitter::emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insOpts instOptions)
{
if (IsMovInstruction(ins))
{
assert(!"Please use emitIns_Mov() to correctly handle move elision");
emitIns_Mov(ins, attr, reg1, reg2, /* canSkip */ false);
}
emitAttr size = EA_SIZE(attr);
assert(size <= EA_64BYTE);
noway_assert(emitVerifyEncodable(ins, size, reg1, reg2));
/* Special case: "XCHG" uses a different format */
insFormat fmt = (ins == INS_xchg) ? IF_RRW_RRW : emitInsModeFormat(ins, IF_RRD_RRD);
instrDesc* id = emitNewInstrSmall(attr);
id->idIns(ins);
id->idInsFmt(fmt);
id->idReg1(reg1);
id->idReg2(reg2);
if ((instOptions & INS_OPTS_EVEX_b_MASK) != INS_OPTS_NONE)
{
// if EVEX.b needs to be set in this path, then it should be embedded rounding.
assert(UseEvexEncoding());
id->idSetEvexbContext(instOptions);
}
UNATIVE_OFFSET sz = emitInsSizeRR(id);
id->idCodeSize(sz);
dispIns(id);
emitCurIGsize += sz;
}
Дальше нам остается просто получить название регистра по его числу - это мы сделали на 1 шаге при их регистрации.
Здесь применяется условная компиляция. Но в рантайме (динамически) это тоже можно реализовать - просто кидаешь везде простые массивы и индексы.