Reserve r11 for code-gen's scratch fallback
This diff reserves r11 for the GP scratch register used by the CodeGenerator (in case no better register is available). rScratch (r10) is now reserved for the assembler, and was renamed to rAsm. This avoids a class of subtle bugs where code-gen mixed uses of rScratch with calls to the assembler that could also make use of this register. (Tx64 code still uses rScratch/rAsm for now.) While here, also moved the reserved XMM scratch registers from the assembler to CodeGenerator, since the assembler doesn't really use them. (The uses of these registers in Tx64 were renamed back to xmm0/xmm1 as they were until recently.)
Esse commit está contido em:
@@ -57,11 +57,11 @@ emitInc(X64Assembler& a, uint64_t* tl_table, uint index, int n,
|
||||
a. jcc8 (ccNegate(cc), jcc);
|
||||
}
|
||||
a. pushf ();
|
||||
a. push (reg::rScratch);
|
||||
a. movq (virtualAddress, reg::rScratch);
|
||||
a. push (reg::rAsm);
|
||||
a. movq (virtualAddress, reg::rAsm);
|
||||
a. fs();
|
||||
a. addq (n, *reg::rScratch);
|
||||
a. pop (reg::rScratch);
|
||||
a. addq (n, *reg::rAsm);
|
||||
a. pop (reg::rAsm);
|
||||
a. popf ();
|
||||
if (havecc) {
|
||||
a. patchJcc8(jcc, a.code.frontier);
|
||||
|
||||
@@ -67,6 +67,9 @@ constexpr PhysReg rVmTl = reg::r12;
|
||||
*/
|
||||
|
||||
const RegSet kCallerSaved = RegSet()
|
||||
// ------------
|
||||
// GP registers
|
||||
// ------------
|
||||
| RegSet(reg::rax)
|
||||
| RegSet(reg::rcx)
|
||||
| RegSet(reg::rdx)
|
||||
@@ -74,12 +77,15 @@ const RegSet kCallerSaved = RegSet()
|
||||
| RegSet(reg::rdi)
|
||||
| RegSet(reg::r8)
|
||||
| RegSet(reg::r9)
|
||||
// r10 is reserved by the assembler, and for
|
||||
// various extremely-specific scratch uses.
|
||||
| RegSet(reg::r11)
|
||||
// XMM regs
|
||||
// | RegSet(reg::xmm0) Reserved for rMMXScratch0
|
||||
// | RegSet(reg::xmm1) Reserved for rMMXScratch1
|
||||
// r10 is reserved for the assembler (rAsm), and for
|
||||
// various extremely-specific scratch uses
|
||||
// r11 is reserved for CodeGenerator (rCgGP)
|
||||
//
|
||||
// -------------
|
||||
// XMM registers
|
||||
// -------------
|
||||
// xmm0 is reserved for CodeGenerator (rCgXMM0)
|
||||
// xmm1 is reserved for CodeGenerator (rCgXMM1)
|
||||
| RegSet(reg::xmm2)
|
||||
| RegSet(reg::xmm3)
|
||||
| RegSet(reg::xmm4)
|
||||
|
||||
@@ -309,7 +309,7 @@ PhysReg CodeGenerator::selectScratchReg(IRInstruction* inst) {
|
||||
if ((kLowGPRegs - liveRegs).findFirst(selectedReg)) {
|
||||
return selectedReg;
|
||||
}
|
||||
return rScratch;
|
||||
return rCgGP;
|
||||
}
|
||||
|
||||
Address CodeGenerator::cgInst(IRInstruction* inst) {
|
||||
@@ -531,7 +531,7 @@ void CodeGenerator::emitLoadImm(CodeGenerator::Asm& as, int64_t val,
|
||||
if (val == 0) {
|
||||
as.pxor_xmm_xmm(dstReg, dstReg);
|
||||
} else {
|
||||
// Can't move immediate directly into XMM register, so use rScratch
|
||||
// Can't move immediate directly into XMM register, so use m_rScratch
|
||||
as.emitImmReg(val, m_rScratch);
|
||||
emitMovRegReg(as, m_rScratch, dstReg);
|
||||
}
|
||||
@@ -613,14 +613,14 @@ static int64_t convIntToDouble(int64_t i) {
|
||||
* Returns a XMM register containing the value of SSATmp tmp,
|
||||
* which can be either a bool, an int, or a double.
|
||||
* If the value is already in a XMM register, simply returns it.
|
||||
* Otherwise, the value is moved into rXMMScratch, which is returned.
|
||||
* Otherwise, the value is moved into rCgXMM, which is returned.
|
||||
* If instructions to convert to a double at runtime are needed,
|
||||
* they're emitted in 'as'.
|
||||
*/
|
||||
PhysReg CodeGenerator::prepXMMReg(const SSATmp* tmp,
|
||||
X64Assembler& as,
|
||||
const RegAllocInfo& allocInfo,
|
||||
RegXMM rXMMScratch) {
|
||||
RegXMM rCgXMM) {
|
||||
assert(tmp->isA(Type::Bool) || tmp->isA(Type::Int) || tmp->isA(Type::Dbl));
|
||||
|
||||
PhysReg reg = allocInfo[tmp].getReg();
|
||||
@@ -632,15 +632,15 @@ PhysReg CodeGenerator::prepXMMReg(const SSATmp* tmp,
|
||||
if (reg != InvalidReg) {
|
||||
// Case 2.a: Dbl stored in GP reg
|
||||
if (tmp->isA(Type::Dbl)) {
|
||||
emitMovRegReg(as, reg, rXMMScratch);
|
||||
return rXMMScratch;
|
||||
emitMovRegReg(as, reg, rCgXMM);
|
||||
return rCgXMM;
|
||||
}
|
||||
// Case 2.b: Bool or Int stored in GP reg
|
||||
assert(tmp->isA(Type::Bool) || tmp->isA(Type::Int));
|
||||
zeroExtendIfBool(as, tmp, allocInfo[tmp]);
|
||||
as.pxor_xmm_xmm(rXMMScratch, rXMMScratch);
|
||||
as.cvtsi2sd_reg64_xmm(reg, rXMMScratch);
|
||||
return rXMMScratch;
|
||||
as.pxor_xmm_xmm(rCgXMM, rCgXMM);
|
||||
as.cvtsi2sd_reg64_xmm(reg, rCgXMM);
|
||||
return rCgXMM;
|
||||
}
|
||||
|
||||
// Case 3: tmp is a constant
|
||||
@@ -653,8 +653,8 @@ PhysReg CodeGenerator::prepXMMReg(const SSATmp* tmp,
|
||||
val = convIntToDouble(val);
|
||||
}
|
||||
emitLoadImm(as, val, m_rScratch);
|
||||
emitMovRegReg(as, m_rScratch, rXMMScratch);
|
||||
return rXMMScratch;
|
||||
emitMovRegReg(as, m_rScratch, rCgXMM);
|
||||
return rCgXMM;
|
||||
}
|
||||
|
||||
void CodeGenerator::doubleCmp(X64Assembler& a, RegXMM xmmReg0, RegXMM xmmReg1) {
|
||||
@@ -717,9 +717,9 @@ void CodeGenerator::emitCompare(SSATmp* src1, SSATmp* src2) {
|
||||
CG_PUNT(emitCompare);
|
||||
}
|
||||
if (src1Type == Type::Dbl || src2Type == Type::Dbl) {
|
||||
PhysReg srcReg1 = prepXMMReg(src1, m_as, m_regs, rXMMScratch0);
|
||||
PhysReg srcReg2 = prepXMMReg(src2, m_as, m_regs, rXMMScratch1);
|
||||
assert(srcReg1 != rXMMScratch1 && srcReg2 != rXMMScratch0);
|
||||
PhysReg srcReg1 = prepXMMReg(src1, m_as, m_regs, rCgXMM0);
|
||||
PhysReg srcReg2 = prepXMMReg(src2, m_as, m_regs, rCgXMM1);
|
||||
assert(srcReg1 != rCgXMM1 && srcReg2 != rCgXMM0);
|
||||
doubleCmp(m_as, srcReg1, srcReg2);
|
||||
} else {
|
||||
auto srcReg1 = m_regs[src1].getReg();
|
||||
@@ -838,12 +838,12 @@ static int64_t shuffleArgs(Asm& a, ArgGroup& args) {
|
||||
}
|
||||
}
|
||||
std::vector<MoveInfo> howTo;
|
||||
doRegMoves(moves, int(reg::rScratch), howTo);
|
||||
doRegMoves(moves, int(rCgGP), howTo);
|
||||
|
||||
// Execute the plan
|
||||
for (size_t i = 0; i < howTo.size(); ++i) {
|
||||
if (howTo[i].m_kind == MoveInfo::Move) {
|
||||
if (howTo[i].m_reg2 == reg::rScratch) {
|
||||
if (howTo[i].m_reg2 == rCgGP) {
|
||||
emitMovRegReg(a, howTo[i].m_reg1, howTo[i].m_reg2);
|
||||
} else {
|
||||
ArgDesc* argDesc = argDescs[int(howTo[i].m_reg2)];
|
||||
@@ -905,12 +905,12 @@ static int64_t shuffleArgs(Asm& a, ArgGroup& args) {
|
||||
switch (arg.getKind()) {
|
||||
case ArgDesc::Reg:
|
||||
if (arg.isZeroExtend()) {
|
||||
a. movzbl(rbyte(srcReg), r32(rScratch));
|
||||
a. push(rScratch);
|
||||
a. movzbl(rbyte(srcReg), r32(rCgGP));
|
||||
a. push(rCgGP);
|
||||
} else {
|
||||
if (srcReg.isXMM()) {
|
||||
emitMovRegReg(a, srcReg, rScratch);
|
||||
a.push(rScratch);
|
||||
emitMovRegReg(a, srcReg, rCgGP);
|
||||
a.push(rCgGP);
|
||||
} else {
|
||||
a.push(srcReg);
|
||||
}
|
||||
@@ -929,16 +929,16 @@ static int64_t shuffleArgs(Asm& a, ArgGroup& args) {
|
||||
} else {
|
||||
// 4 bytes of garbage:
|
||||
a. pushl(eax);
|
||||
// get the type in the right place in rScratch before pushing it
|
||||
a. movb (rbyte(srcReg), rbyte(rScratch));
|
||||
a. shll (CHAR_BIT, r32(rScratch));
|
||||
a. pushl(r32(rScratch));
|
||||
// get the type in the right place in rCgGP before pushing it
|
||||
a. movb (rbyte(srcReg), rbyte(rCgGP));
|
||||
a. shll (CHAR_BIT, r32(rCgGP));
|
||||
a. pushl(r32(rCgGP));
|
||||
}
|
||||
break;
|
||||
|
||||
case ArgDesc::Imm:
|
||||
a. emitImmReg(arg.getImm(), rScratch);
|
||||
a. push(rScratch);
|
||||
a. emitImmReg(arg.getImm(), rCgGP);
|
||||
a. push(rCgGP);
|
||||
break;
|
||||
|
||||
case ArgDesc::Addr:
|
||||
@@ -1259,12 +1259,12 @@ void CodeGenerator::cgBinaryOp(IRInstruction* inst,
|
||||
if (src1->isA(Type::Dbl) || src2->isA(Type::Dbl)) {
|
||||
PhysReg dstReg = m_regs[dst].getReg();
|
||||
PhysReg resReg = dstReg.isXMM() && dstReg != m_regs[src2].getReg() ?
|
||||
dstReg : PhysReg(rXMMScratch0);
|
||||
dstReg : PhysReg(rCgXMM0);
|
||||
assert(resReg.isXMM());
|
||||
|
||||
PhysReg srcReg1 = prepXMMReg(src1, m_as, m_regs, resReg);
|
||||
PhysReg srcReg2 = prepXMMReg(src2, m_as, m_regs, rXMMScratch1);
|
||||
assert(srcReg1 != rXMMScratch1 && srcReg2 != rXMMScratch0);
|
||||
PhysReg srcReg2 = prepXMMReg(src2, m_as, m_regs, rCgXMM1);
|
||||
assert(srcReg1 != rCgXMM1 && srcReg2 != rCgXMM0);
|
||||
|
||||
emitMovRegReg(m_as, srcReg1, resReg);
|
||||
|
||||
@@ -1550,9 +1550,9 @@ void CodeGenerator::cgOpCmpHelper(
|
||||
else if (type1 == Type::Dbl || type2 == Type::Dbl) {
|
||||
if ((type1 == Type::Dbl || type1 == Type::Int) &&
|
||||
(type2 == Type::Dbl || type2 == Type::Int)) {
|
||||
PhysReg srcReg1 = prepXMMReg(src1, m_as, m_regs, rXMMScratch0);
|
||||
PhysReg srcReg2 = prepXMMReg(src2, m_as, m_regs, rXMMScratch1);
|
||||
assert(srcReg1 != rXMMScratch1 && srcReg2 != rXMMScratch0);
|
||||
PhysReg srcReg1 = prepXMMReg(src1, m_as, m_regs, rCgXMM0);
|
||||
PhysReg srcReg2 = prepXMMReg(src2, m_as, m_regs, rCgXMM1);
|
||||
assert(srcReg1 != rCgXMM1 && srcReg2 != rCgXMM0);
|
||||
doubleCmp(m_as, srcReg1, srcReg2);
|
||||
setFromFlags();
|
||||
} else {
|
||||
@@ -1967,7 +1967,7 @@ void CodeGenerator::emitConvBoolOrIntToDbl(IRInstruction* inst) {
|
||||
// cause false dependencies to prevent register renaming from kicking
|
||||
// in. Break the dependency chain by zeroing out the XMM reg.
|
||||
PhysReg srcReg = m_regs[src].getReg();
|
||||
PhysReg xmmReg = dstReg.isXMM() ? dstReg : PhysReg(rXMMScratch0);
|
||||
PhysReg xmmReg = dstReg.isXMM() ? dstReg : PhysReg(rCgXMM0);
|
||||
m_as.pxor_xmm_xmm(xmmReg, xmmReg);
|
||||
m_as.cvtsi2sd_reg64_xmm(srcReg, xmmReg);
|
||||
zeroExtendIfBool(m_as, src, m_regs[src]);
|
||||
|
||||
@@ -112,6 +112,10 @@ struct CodegenState {
|
||||
AsmInfo* asmInfo;
|
||||
};
|
||||
|
||||
constexpr Reg64 rCgGP (reg::r11);
|
||||
constexpr RegXMM rCgXMM0(reg::xmm0);
|
||||
constexpr RegXMM rCgXMM1(reg::xmm1);
|
||||
|
||||
struct CodeGenerator {
|
||||
typedef Transl::X64Assembler Asm;
|
||||
|
||||
|
||||
@@ -284,13 +284,14 @@ LinearScan::LinearScan(IRFactory* irFactory)
|
||||
}
|
||||
|
||||
// Mark reserved regs.
|
||||
m_regs[int(PhysReg(rVmSp))] .m_reserved = true;
|
||||
m_regs[int(PhysReg(rsp))] .m_reserved = true;
|
||||
m_regs[int(PhysReg(rVmFp))] .m_reserved = true;
|
||||
m_regs[int(PhysReg(rScratch))] .m_reserved = true;
|
||||
m_regs[int(PhysReg(rVmTl))] .m_reserved = true;
|
||||
m_regs[int(PhysReg(rXMMScratch0))].m_reserved = true;
|
||||
m_regs[int(PhysReg(rXMMScratch1))].m_reserved = true;
|
||||
m_regs[int(PhysReg(rVmSp))] .m_reserved = true;
|
||||
m_regs[int(PhysReg(rsp))] .m_reserved = true;
|
||||
m_regs[int(PhysReg(rVmFp))] .m_reserved = true;
|
||||
m_regs[int(PhysReg(rAsm))] .m_reserved = true;
|
||||
m_regs[int(PhysReg(rVmTl))] .m_reserved = true;
|
||||
m_regs[int(PhysReg(rCgGP))] .m_reserved = true;
|
||||
m_regs[int(PhysReg(rCgXMM0))].m_reserved = true;
|
||||
m_regs[int(PhysReg(rCgXMM1))].m_reserved = true;
|
||||
|
||||
// Reserve extra regs for testing purpose.
|
||||
uint32_t numFreeRegs = RuntimeOption::EvalHHIRNumFreeRegs;
|
||||
|
||||
@@ -656,8 +656,8 @@ emitStoreImm(X64Assembler& a, uint64_t imm, PhysReg r, int off,
|
||||
a. store_imm64_disp_reg64(imm, off, r);
|
||||
return;
|
||||
}
|
||||
emitImmReg(a, imm, rScratch);
|
||||
immReg = rScratch;
|
||||
emitImmReg(a, imm, rAsm);
|
||||
immReg = rAsm;
|
||||
}
|
||||
a. store_reg64_disp_reg64(immReg, off, r);
|
||||
} else if (size == sz::dword) {
|
||||
@@ -905,8 +905,8 @@ inline void emitCopyToAligned(X64Assembler& a,
|
||||
int destOff) {
|
||||
static_assert(sizeof(TypedValue) == 16,
|
||||
"emitCopyToAligned assumes sizeof(TypedValue) is 128 bits");
|
||||
a. movdqa (src[srcOff], rXMMScratch0);
|
||||
a. movdqa (rXMMScratch0, dest[destOff]);
|
||||
a. movdqa (src[srcOff], xmm0);
|
||||
a. movdqa (xmm0, dest[destOff]);
|
||||
}
|
||||
|
||||
// ArgManager -- support for passing VM-level data to helper functions.
|
||||
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -759,7 +759,7 @@ TranslatorX64::emitEagerSyncPoint(X64Assembler& a, const Opcode* pc,
|
||||
static COff fpOff = offsetof(VMExecutionContext, m_fp);
|
||||
static COff pcOff = offsetof(VMExecutionContext, m_pc);
|
||||
|
||||
/* we can't use rScratch because the pc store uses it as a
|
||||
/* we can't use rAsm because the pc store uses it as a
|
||||
temporary */
|
||||
Reg64 rEC = reg::rdi;
|
||||
|
||||
@@ -767,8 +767,8 @@ TranslatorX64::emitEagerSyncPoint(X64Assembler& a, const Opcode* pc,
|
||||
emitGetGContext(a, rEC);
|
||||
a. storeq(rVmFp, rEC[fpOff]);
|
||||
if (spDiff) {
|
||||
a. lea(rVmSp[spDiff], rScratch);
|
||||
a. storeq(rScratch, rEC[spOff]);
|
||||
a. lea(rVmSp[spDiff], rAsm);
|
||||
a. storeq(rAsm, rEC[spOff]);
|
||||
} else {
|
||||
a. storeq(rVmSp, rEC[spOff]);
|
||||
}
|
||||
@@ -949,7 +949,7 @@ emitEagerVMRegSave(X64Assembler& a,
|
||||
assert((flags & ~(SavePC | SaveFP)) == 0);
|
||||
|
||||
Reg64 pcReg = rdi;
|
||||
PhysReg rEC = rScratch;
|
||||
PhysReg rEC = rAsm;
|
||||
assert(!kSpecialCrossTraceRegs.contains(rdi));
|
||||
|
||||
emitGetGContext(a, rEC);
|
||||
@@ -1131,13 +1131,13 @@ void TranslatorX64::emitDecRefGeneric(const NormalizedInstruction& i,
|
||||
void TranslatorX64::emitDecRefGenericReg(PhysReg rData, PhysReg rType) {
|
||||
SpaceRecorder sr("_DecRefGeneric", a);
|
||||
|
||||
assert(rData != rScratch && rType != rScratch);
|
||||
assert(rData != rAsm && rType != rAsm);
|
||||
|
||||
auto body = [&](X64Assembler& a){
|
||||
// Calling convention: m_data in rdi, m_type in r10 (rScratch).
|
||||
// Calling convention: m_data in rdi, m_type in r10 (rAsm).
|
||||
// (See emitGenericDecRefHelpers.)
|
||||
assert(!kAllRegs.contains(rScratch));
|
||||
a. movl (r32(rType), r32(rScratch));
|
||||
assert(!kAllRegs.contains(rAsm));
|
||||
a. movl (r32(rType), r32(rAsm));
|
||||
callUnaryReentrantStub(a, *m_curNI, m_dtorGenericStubRegs, rData);
|
||||
};
|
||||
|
||||
@@ -1212,15 +1212,15 @@ void TranslatorX64::emitGenericDecRefHelpers() {
|
||||
emitMovRegReg(a, rVmSp, rdi);
|
||||
// fall through
|
||||
m_dtorGenericStub = a.code.frontier;
|
||||
emitLoadTVType(a, rdi[TVOFF(m_type)], r32(rScratch));
|
||||
emitLoadTVType(a, rdi[TVOFF(m_type)], r32(rAsm));
|
||||
a. loadq (rdi[TVOFF(m_data)], rdi);
|
||||
// Fall through to the regs stub.
|
||||
|
||||
/*
|
||||
* Custom calling convention: m_type goes in rScratch, m_data in
|
||||
* rdi. We don't ever store program locations in rScratch, so the
|
||||
* Custom calling convention: m_type goes in rAsm, m_data in
|
||||
* rdi. We don't ever store program locations in rAsm, so the
|
||||
* caller didn't need to spill anything. The assembler sometimes
|
||||
* uses rScratch, but we know the stub won't need to and it makes it
|
||||
* uses rAsm, but we know the stub won't need to and it makes it
|
||||
* possible to share the code for both decref helpers.
|
||||
*/
|
||||
m_dtorGenericStubRegs = a.code.frontier;
|
||||
@@ -1234,7 +1234,7 @@ void TranslatorX64::emitGenericDecRefHelpers() {
|
||||
asm_label(a, release);
|
||||
{
|
||||
PhysRegSaver prs(a, kGPCallerSaved - RegSet(rdi));
|
||||
callDestructor(a, rScratch, rax);
|
||||
callDestructor(a, rAsm, rax);
|
||||
recordIndirectFixup(a.code.frontier, prs.rspAdjustment());
|
||||
}
|
||||
a. ret ();
|
||||
@@ -1571,9 +1571,9 @@ TranslatorX64::emitStackCheck(int funcDepth, Offset pc) {
|
||||
funcDepth += kStackCheckPadding * sizeof(Cell);
|
||||
|
||||
uint64_t stackMask = cellsToBytes(RuntimeOption::EvalVMStackElms) - 1;
|
||||
a. mov_reg64_reg64(rVmSp, rScratch); // copy to destroy
|
||||
a. and_imm64_reg64(stackMask, rScratch);
|
||||
a. sub_imm64_reg64(funcDepth + Stack::sSurprisePageSize, rScratch);
|
||||
a. mov_reg64_reg64(rVmSp, rAsm); // copy to destroy
|
||||
a. and_imm64_reg64(stackMask, rAsm);
|
||||
a. sub_imm64_reg64(funcDepth + Stack::sSurprisePageSize, rAsm);
|
||||
assert(m_stackOverflowHelper);
|
||||
a. jl(m_stackOverflowHelper); // Unlikely branch to failure.
|
||||
// Success.
|
||||
@@ -2180,23 +2180,23 @@ TranslatorX64::emitPrologue(Func* func, int nPassed) {
|
||||
a. loadq(rVmFp[AROFF(m_this)], rClosure);
|
||||
|
||||
// Swap in the $this or late bound class
|
||||
a. loadq(rClosure[c_Closure::thisOffset()], rScratch);
|
||||
a. storeq(rScratch, rVmFp[AROFF(m_this)]);
|
||||
a. loadq(rClosure[c_Closure::thisOffset()], rAsm);
|
||||
a. storeq(rAsm, rVmFp[AROFF(m_this)]);
|
||||
|
||||
a. shrq(1, rScratch);
|
||||
a. shrq(1, rAsm);
|
||||
if (func->attrs() & AttrStatic) {
|
||||
UnlikelyIfBlock ifRealThis(CC_NBE, a, astubs);
|
||||
astubs.shlq(1, rScratch);
|
||||
emitIncRef(astubs, rScratch, KindOfObject);
|
||||
astubs.shlq(1, rAsm);
|
||||
emitIncRef(astubs, rAsm, KindOfObject);
|
||||
} else {
|
||||
JccBlock<CC_BE> ifRealThis(a);
|
||||
a.shlq(1, rScratch);
|
||||
emitIncRef(rScratch, KindOfObject);
|
||||
a.shlq(1, rAsm);
|
||||
emitIncRef(rAsm, KindOfObject);
|
||||
}
|
||||
|
||||
// Put in the correct context
|
||||
a. loadq(rClosure[c_Closure::funcOffset()], rScratch);
|
||||
a. storeq(rScratch, rVmFp[AROFF(m_func)]);
|
||||
a. loadq(rClosure[c_Closure::funcOffset()], rAsm);
|
||||
a. storeq(rAsm, rVmFp[AROFF(m_func)]);
|
||||
|
||||
// Copy in all the use vars
|
||||
int baseUVOffset = sizeof(ObjectData) + func->cls()->builtinPropSize();
|
||||
@@ -2213,8 +2213,8 @@ TranslatorX64::emitPrologue(Func* func, int nPassed) {
|
||||
|
||||
int uvOffset = baseUVOffset + cellsToBytes(i-1);
|
||||
|
||||
emitCopyTo(a, rClosure, uvOffset, rVmSp, spOffset, rScratch);
|
||||
emitIncRefGenericRegSafe(rVmSp, spOffset, rScratch);
|
||||
emitCopyTo(a, rClosure, uvOffset, rVmSp, spOffset, rAsm);
|
||||
emitIncRefGenericRegSafe(rVmSp, spOffset, rAsm);
|
||||
}
|
||||
|
||||
numLocals += numUseVars + 1;
|
||||
@@ -3285,7 +3285,7 @@ TranslatorX64::emitServiceReqVA(SRFlags flags, ServiceRequest req, int numArgs,
|
||||
}
|
||||
|
||||
if (notReusable) {
|
||||
emitImmReg(as, 0, rScratch);
|
||||
emitImmReg(as, 0, rAsm);
|
||||
} else {
|
||||
/*
|
||||
* Make sure that the stub has enough space so it can be reused
|
||||
@@ -3293,7 +3293,7 @@ TranslatorX64::emitServiceReqVA(SRFlags flags, ServiceRequest req, int numArgs,
|
||||
* alignment, etc.
|
||||
*/
|
||||
as.emitNop(start + kMaxStubSpace - as.code.frontier);
|
||||
emitImmReg(as, (uint64_t)start, rScratch);
|
||||
emitImmReg(as, (uint64_t)start, rAsm);
|
||||
}
|
||||
TRACE(3, ")\n");
|
||||
emitImmReg(as, req, rdi);
|
||||
@@ -3341,9 +3341,9 @@ TranslatorX64::emitTransCounterInc(X64Assembler& a) {
|
||||
TCA start = a.code.frontier;
|
||||
if (!isTransDBEnabled()) return start;
|
||||
|
||||
a. movq (getTransCounterAddr(), rScratch);
|
||||
a. movq (getTransCounterAddr(), rAsm);
|
||||
a. lock ();
|
||||
a. incq (*rScratch);
|
||||
a. incq (*rAsm);
|
||||
|
||||
return start;
|
||||
}
|
||||
@@ -3549,17 +3549,17 @@ TranslatorX64::binaryMixedArith(const NormalizedInstruction& i,
|
||||
Opcode op,
|
||||
PhysReg srcReg,
|
||||
PhysReg srcDestReg) {
|
||||
getInputsIntoXMMRegs(i, srcReg, srcDestReg, rXMMScratch1, rXMMScratch0);
|
||||
getInputsIntoXMMRegs(i, srcReg, srcDestReg, xmm1, xmm0);
|
||||
switch(op) {
|
||||
#define CASEIMM(OpBc, x64op) \
|
||||
case OpBc: a. x64op ##sd_xmm_xmm(rXMMScratch1, rXMMScratch0); break
|
||||
case OpBc: a. x64op ##sd_xmm_xmm(xmm1, xmm0); break
|
||||
CASEIMM(OpAdd, add);
|
||||
CASEIMM(OpSub, sub);
|
||||
CASEIMM(OpMul, mul);
|
||||
#undef CASEIMM
|
||||
default: not_reached();
|
||||
}
|
||||
a. mov_xmm_reg64(rXMMScratch0, srcDestReg);
|
||||
a. mov_xmm_reg64(xmm0, srcDestReg);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -4002,13 +4002,13 @@ TranslatorX64::analyzeEqOp(Tracelet& t, NormalizedInstruction& i) {
|
||||
void
|
||||
TranslatorX64::fpEq(const NormalizedInstruction& ni,
|
||||
PhysReg lr, PhysReg rr) {
|
||||
getInputsIntoXMMRegs(ni, lr, rr, rXMMScratch0, rXMMScratch1);
|
||||
getInputsIntoXMMRegs(ni, lr, rr, xmm0, xmm1);
|
||||
m_regMap.allocOutputRegs(ni);
|
||||
a. ucomisd_xmm_xmm(rXMMScratch0, rXMMScratch1);
|
||||
a. ucomisd_xmm_xmm(xmm0, xmm1);
|
||||
semiLikelyIfBlock(CC_P, a, [&] {
|
||||
// PF means unordered; treat it as !eq. Or 1 into anything at all
|
||||
// to clear ZF.
|
||||
a. or_imm32_reg64(1, reg::rScratch);
|
||||
a. or_imm32_reg64(1, reg::rAsm);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5915,10 +5915,10 @@ TranslatorX64::translateJmp(const Tracelet& t,
|
||||
if (trustSigSegv) {
|
||||
const uint64_t stackMask =
|
||||
~(cellsToBytes(RuntimeOption::EvalVMStackElms) - 1);
|
||||
a.mov_reg64_reg64(rVmSp, rScratch);
|
||||
a.and_imm64_reg64(stackMask, rScratch);
|
||||
a.mov_reg64_reg64(rVmSp, rAsm);
|
||||
a.and_imm64_reg64(stackMask, rAsm);
|
||||
TCA surpriseLoad = a.code.frontier;
|
||||
a.load_reg64_disp_reg64(rScratch, 0, rScratch);
|
||||
a.load_reg64_disp_reg64(rAsm, 0, rAsm);
|
||||
|
||||
if (!m_segvStubs.insert(SignalStubMap::value_type(surpriseLoad,
|
||||
astubs.code.frontier)))
|
||||
@@ -6116,9 +6116,9 @@ TranslatorX64::translateSwitch(const Tracelet& t,
|
||||
TCA afterLea = a.code.frontier + kLeaRipLen;
|
||||
ptrdiff_t diff = (TCA)jmptab - afterLea;
|
||||
assert(deltaFits(diff, sz::dword));
|
||||
a. lea (rip[diff], rScratch);
|
||||
a. lea (rip[diff], rAsm);
|
||||
assert(a.code.frontier == afterLea);
|
||||
a. jmp (rScratch[valReg*8]);
|
||||
a. jmp (rAsm[valReg*8]);
|
||||
|
||||
for (int idx = 0; idx < jmptabSize; ++idx) {
|
||||
SrcKey sk(curFunc(), i.offset() + iv.vec32()[idx]);
|
||||
@@ -7022,9 +7022,9 @@ void TranslatorX64::translateCreateCont(const Tracelet& t,
|
||||
ContParamMap params;
|
||||
if (origLocals <= kMaxInlineContLocals &&
|
||||
mapContParams(params, origFunc, genFunc)) {
|
||||
ScratchReg rScratch(m_regMap);
|
||||
a. load_reg64_disp_reg64(rVmFp, AROFF(m_varEnv), r(rScratch));
|
||||
a. test_reg64_reg64(r(rScratch), r(rScratch));
|
||||
ScratchReg rAsm(m_regMap);
|
||||
a. load_reg64_disp_reg64(rVmFp, AROFF(m_varEnv), r(rAsm));
|
||||
a. test_reg64_reg64(r(rAsm), r(rAsm));
|
||||
DiamondReturn astubsRet;
|
||||
{
|
||||
UnlikelyIfBlock ifVarEnv(CC_NZ, a, astubs, &astubsRet);
|
||||
@@ -7048,22 +7048,22 @@ void TranslatorX64::translateCreateCont(const Tracelet& t,
|
||||
for (int i = 0; i < origLocals; ++i) {
|
||||
assert(mapContains(params, i));
|
||||
int destOff = cellsToBytes(genLocals - params[i] - 1);
|
||||
emitCopyTo(a, rVmFp, localOffset(i), r(rDest), destOff, r(rScratch));
|
||||
emitIncRefGenericRegSafe(r(rDest), destOff, r(rScratch));
|
||||
emitCopyTo(a, rVmFp, localOffset(i), r(rDest), destOff, r(rAsm));
|
||||
emitIncRefGenericRegSafe(r(rDest), destOff, r(rAsm));
|
||||
}
|
||||
|
||||
// Deal with a potential $this local in the generator body
|
||||
if (fillThis) {
|
||||
assert(thisId != kInvalidId);
|
||||
a. load_reg64_disp_reg64(rax, CONTOFF(m_obj), r(rScratch));
|
||||
a. test_reg64_reg64(r(rScratch), r(rScratch));
|
||||
a. load_reg64_disp_reg64(rax, CONTOFF(m_obj), r(rAsm));
|
||||
a. test_reg64_reg64(r(rAsm), r(rAsm));
|
||||
{
|
||||
JccBlock<CC_Z> ifObj(a);
|
||||
const int thisOff = cellsToBytes(genLocals - thisId - 1);
|
||||
// We don't have to check for a static refcount since we
|
||||
// know it's an Object
|
||||
a. incl(r(rScratch)[FAST_REFCOUNT_OFFSET]);
|
||||
a. storeq(r(rScratch), r(rDest)[thisOff + TVOFF(m_data)]);
|
||||
a. incl(r(rAsm)[FAST_REFCOUNT_OFFSET]);
|
||||
a. storeq(r(rAsm), r(rDest)[thisOff + TVOFF(m_data)]);
|
||||
emitStoreTVType(a, KindOfObject, r(rDest)[thisOff + TVOFF(m_type)]);
|
||||
}
|
||||
}
|
||||
@@ -7083,9 +7083,9 @@ void TranslatorX64::translateUnpackCont(const Tracelet& t,
|
||||
assert(i.inputs[contIdx]->location == Location(Location::Local, 0));
|
||||
assert(i.outStack->outerType() == KindOfInt64);
|
||||
|
||||
ScratchReg rScratch(m_regMap);
|
||||
a. load_reg64_disp_reg64(rVmFp, AROFF(m_varEnv), r(rScratch));
|
||||
a. test_reg64_reg64(r(rScratch), r(rScratch));
|
||||
ScratchReg rAsm(m_regMap);
|
||||
a. load_reg64_disp_reg64(rVmFp, AROFF(m_varEnv), r(rAsm));
|
||||
a. test_reg64_reg64(r(rAsm), r(rAsm));
|
||||
{
|
||||
UnlikelyIfBlock hasVars(CC_NZ, a, astubs);
|
||||
Stats::emitInc(astubs, Stats::Tx64_ContUnpackSlow);
|
||||
@@ -7123,9 +7123,9 @@ void TranslatorX64::translatePackCont(const Tracelet& t,
|
||||
const int valIdx = 0;
|
||||
const int contIdx = 1;
|
||||
|
||||
ScratchReg rScratch(m_regMap);
|
||||
a. load_reg64_disp_reg64(rVmFp, AROFF(m_varEnv), r(rScratch));
|
||||
a. test_reg64_reg64(r(rScratch), r(rScratch));
|
||||
ScratchReg rAsm(m_regMap);
|
||||
a. load_reg64_disp_reg64(rVmFp, AROFF(m_varEnv), r(rAsm));
|
||||
a. test_reg64_reg64(r(rAsm), r(rAsm));
|
||||
{
|
||||
// TODO: Task #1132976: We can probably prove that this is impossible in
|
||||
// most cases using information from hphpc
|
||||
@@ -7143,8 +7143,8 @@ void TranslatorX64::translatePackCont(const Tracelet& t,
|
||||
emitTvSet(i, rValue, i.inputs[valIdx]->outerType(),
|
||||
rCont, CONTOFF(m_value), false);
|
||||
|
||||
emitImmReg(a, i.imm[0].u_IVA, r(rScratch));
|
||||
a. store_reg64_disp_reg64(r(rScratch), CONTOFF(m_label), rCont);
|
||||
emitImmReg(a, i.imm[0].u_IVA, r(rAsm));
|
||||
a. store_reg64_disp_reg64(r(rAsm), CONTOFF(m_label), rCont);
|
||||
}
|
||||
|
||||
static void continuationRaiseHelper(c_Continuation* cont) {
|
||||
@@ -7177,9 +7177,9 @@ void TranslatorX64::translateContReceive(const Tracelet& t,
|
||||
const int contIdx = 0;
|
||||
emitContRaiseCheck(a, i);
|
||||
PhysReg rCont = getReg(i.inputs[contIdx]->location);
|
||||
ScratchReg rScratch(m_regMap);
|
||||
emitLea(a, rCont, CONTOFF(m_received), r(rScratch));
|
||||
emitCopyToStack(a, i, r(rScratch), -1 * (int)sizeof(Cell));
|
||||
ScratchReg rAsm(m_regMap);
|
||||
emitLea(a, rCont, CONTOFF(m_received), r(rAsm));
|
||||
emitCopyToStack(a, i, r(rAsm), -1 * (int)sizeof(Cell));
|
||||
emitStoreUninitNull(a, CONTOFF(m_received), rCont);
|
||||
}
|
||||
|
||||
@@ -7387,10 +7387,10 @@ void TranslatorX64::translateStrlen(const Tracelet& t,
|
||||
// Nothing. strlen(true) == 1, strlen(false) == 0
|
||||
break;
|
||||
STRINGCASE(): {
|
||||
ScratchReg rScratch(m_regMap);
|
||||
a. load_reg64_disp_reg32(rInput, StringData::sizeOffset(), r(rScratch));
|
||||
ScratchReg rAsm(m_regMap);
|
||||
a. load_reg64_disp_reg32(rInput, StringData::sizeOffset(), r(rAsm));
|
||||
emitDecRef(a, i, rInput, inType);
|
||||
m_regMap.bindScratch(rScratch, i.outStack->location, KindOfInt64,
|
||||
m_regMap.bindScratch(rAsm, i.outStack->location, KindOfInt64,
|
||||
RegInfo::DIRTY);
|
||||
assert(m_regMap.regIsFree(rInput));
|
||||
break;
|
||||
@@ -8357,9 +8357,9 @@ TranslatorX64::emitNativeTrampoline(TCA helperAddr) {
|
||||
}
|
||||
|
||||
/*
|
||||
* For stubs that take arguments in rScratch, we need to make sure
|
||||
* For stubs that take arguments in rAsm, we need to make sure
|
||||
* we're not damaging its contents here. (If !jmpDeltaFits, the jmp
|
||||
* opcode will need to movabs the address into rScratch before
|
||||
* opcode will need to movabs the address into rAsm before
|
||||
* jumping.)
|
||||
*/
|
||||
auto UNUSED stubUsingRScratch = [&](TCA tca) {
|
||||
@@ -9788,8 +9788,8 @@ void TranslatorX64::translateFCallBuiltin(const Tracelet& t,
|
||||
if (pi.builtinType() == KindOfUnknown) {
|
||||
emitDecRefGeneric(ni, base, disp);
|
||||
} else if (IS_REFCOUNTED_TYPE(pi.builtinType())) {
|
||||
a. loadq (base[disp + TVOFF(m_data)], rScratch);
|
||||
emitDecRef(ni, rScratch, pi.builtinType());
|
||||
a. loadq (base[disp + TVOFF(m_data)], rAsm);
|
||||
emitDecRef(ni, rAsm, pi.builtinType());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11685,11 +11685,11 @@ bool TranslatorX64::addDbgGuard(const Func* func, Offset offset) {
|
||||
void TranslatorX64::addDbgGuardImpl(SrcKey sk, SrcRec& srcRec) {
|
||||
TCA dbgGuard = a.code.frontier;
|
||||
// Emit the checks for debugger attach
|
||||
emitTLSLoad<ThreadInfo>(a, ThreadInfo::s_threadInfo, rScratch);
|
||||
emitTLSLoad<ThreadInfo>(a, ThreadInfo::s_threadInfo, rAsm);
|
||||
static COff dbgOff = offsetof(ThreadInfo, m_reqInjectionData) +
|
||||
RequestInjectionData::debuggerReadOnlyOffset();
|
||||
a. load_reg64_disp_reg32(rScratch, dbgOff, rScratch);
|
||||
a. testb((int8_t)0xff, rbyte(rScratch));
|
||||
a. load_reg64_disp_reg32(rAsm, dbgOff, rAsm);
|
||||
a. testb((int8_t)0xff, rbyte(rAsm));
|
||||
// Branch to a special REQ_INTERPRET if attached
|
||||
{
|
||||
TCA fallback = emitServiceReq(REQ_INTERPRET, 2, uint64_t(sk.offset()), 0);
|
||||
|
||||
+24
-26
@@ -412,10 +412,8 @@ namespace reg {
|
||||
constexpr RegXMM xmm14(14);
|
||||
constexpr RegXMM xmm15(15);
|
||||
|
||||
// rScratch, rXMMScratch[01] are symbolic names for regs that are always free
|
||||
constexpr Reg64 rScratch(r10);
|
||||
constexpr RegXMM rXMMScratch0(xmm0);
|
||||
constexpr RegXMM rXMMScratch1(xmm1);
|
||||
// rAsm is the symbolic name for a reg that is reserved for the assembler
|
||||
constexpr Reg64 rAsm(r10);
|
||||
|
||||
#define X(x) if (r == x) return "%"#x
|
||||
inline const char* regname(Reg64 r) {
|
||||
@@ -947,30 +945,30 @@ struct X64Assembler {
|
||||
/*
|
||||
* For when we a have a memory operand and the operand size is
|
||||
* 64-bits, only a 32-bit (sign-extended) immediate is supported.
|
||||
* If the immediate is too big, we'll move it into rScratch first.
|
||||
* If the immediate is too big, we'll move it into rAsm first.
|
||||
*/
|
||||
#define IMM64_STORE_OP(name, instr) \
|
||||
void name##q(Immed i, MemoryRef m) { \
|
||||
if (i.fits(sz::dword)) { \
|
||||
return instrIM(instr, i, m); \
|
||||
} \
|
||||
movq (i, reg::rScratch); \
|
||||
name##q(reg::rScratch, m); \
|
||||
movq (i, reg::rAsm); \
|
||||
name##q(reg::rAsm, m); \
|
||||
} \
|
||||
\
|
||||
void name##q(Immed i, IndexedMemoryRef m) { \
|
||||
if (i.fits(sz::dword)) { \
|
||||
return instrIM(instr, i, m); \
|
||||
} \
|
||||
movq (i, reg::rScratch); \
|
||||
name##q(reg::rScratch, m); \
|
||||
movq (i, reg::rAsm); \
|
||||
name##q(reg::rAsm, m); \
|
||||
}
|
||||
|
||||
/*
|
||||
* For instructions other than movq, even when the operand size is
|
||||
* 64 bits only a 32-bit (sign-extended) immediate is supported. We
|
||||
* provide foo##q instructions that may emit multiple x64
|
||||
* instructions (smashing rScratch) if the immediate does not
|
||||
* instructions (smashing rAsm) if the immediate does not
|
||||
* actually fit in a long.
|
||||
*/
|
||||
#define IMM64R_OP(name, instr) \
|
||||
@@ -978,8 +976,8 @@ struct X64Assembler {
|
||||
if (imm.fits(sz::dword)) { \
|
||||
return instrIR(instr, imm, r); \
|
||||
} \
|
||||
movq (imm, reg::rScratch); \
|
||||
name##q(reg::rScratch, r); \
|
||||
movq (imm, reg::rAsm); \
|
||||
name##q(reg::rAsm, r); \
|
||||
}
|
||||
|
||||
#define FULL_OP(name, instr) \
|
||||
@@ -1044,8 +1042,8 @@ struct X64Assembler {
|
||||
void imul(Reg64 r1, Reg64 r2) { instrRR(instr_imul, r1, r2); }
|
||||
|
||||
void imul(Immed im, Reg64 r1) {
|
||||
movq(im, reg::rScratch);
|
||||
imul(reg::rScratch, r1);
|
||||
movq(im, reg::rAsm);
|
||||
imul(reg::rAsm, r1);
|
||||
}
|
||||
|
||||
void push(Reg64 r) { instrR(instr_push, r); }
|
||||
@@ -1118,21 +1116,21 @@ struct X64Assembler {
|
||||
|
||||
void jmp8(CodeAddress dest) { emitJ8(instr_jmp, ssize_t(dest)); }
|
||||
|
||||
// May smash rScratch.
|
||||
// May smash rAsm.
|
||||
void jmp(CodeAddress dest) {
|
||||
if (!jmpDeltaFits(dest)) {
|
||||
movq (dest, reg::rScratch);
|
||||
jmp (reg::rScratch);
|
||||
movq (dest, reg::rAsm);
|
||||
jmp (reg::rAsm);
|
||||
return;
|
||||
}
|
||||
emitJ32(instr_jmp, ssize_t(dest));
|
||||
}
|
||||
|
||||
// May smash rScratch.
|
||||
// May smash rAsm.
|
||||
void call(CodeAddress dest) {
|
||||
if (!jmpDeltaFits(dest)) {
|
||||
movq (dest, reg::rScratch);
|
||||
call (reg::rScratch);
|
||||
movq (dest, reg::rAsm);
|
||||
call (reg::rAsm);
|
||||
return;
|
||||
}
|
||||
emitJ32(instr_call, ssize_t(dest));
|
||||
@@ -1945,8 +1943,8 @@ public:
|
||||
if (deltaFits(imm, sz::dword)) {
|
||||
emitIM(instr_mov, rdest, reg::noreg, sz::byte, off, imm);
|
||||
} else {
|
||||
mov_imm64_reg(imm, reg::rScratch);
|
||||
emitRM(instr_mov, rdest, reg::noreg, sz::byte, off, reg::rScratch);
|
||||
mov_imm64_reg(imm, reg::rAsm);
|
||||
emitRM(instr_mov, rdest, reg::noreg, sz::byte, off, reg::rAsm);
|
||||
}
|
||||
}
|
||||
// mov %rsrc, disp(%rdest)
|
||||
@@ -2043,8 +2041,8 @@ public:
|
||||
name ## _imm32_reg64(imm, rdest); \
|
||||
return; \
|
||||
} \
|
||||
mov_imm64_reg(imm, reg::rScratch); \
|
||||
name ## _reg64_reg64(reg::rScratch, rdest); \
|
||||
mov_imm64_reg(imm, reg::rAsm); \
|
||||
name ## _reg64_reg64(reg::rAsm, rdest); \
|
||||
} \
|
||||
/* opq rsrc, disp(rdest) */ \
|
||||
inline void name ## _reg64_disp_reg64(RegNumber rsrc, int disp, \
|
||||
@@ -2110,8 +2108,8 @@ public:
|
||||
|
||||
// imul imm, rdest
|
||||
inline void imul_imm64_reg64(int64_t imm, RegNumber rdest) {
|
||||
mov_imm64_reg(imm, reg::rScratch);
|
||||
imul_reg64_reg64(reg::rScratch, rdest);
|
||||
mov_imm64_reg(imm, reg::rAsm);
|
||||
imul_reg64_reg64(reg::rAsm, rdest);
|
||||
}
|
||||
|
||||
inline void xchg_reg64_reg64(RegNumber rsrc, RegNumber rdest) {
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário