Skip to content

Commit 607f220

Browse files
committed
Force spill rax/rcx before Yield so that we don't have to save them
1 parent 9cf6b2f commit 607f220

File tree

3 files changed

+78
-112
lines changed

3 files changed

+78
-112
lines changed

lib/Backend/LinearScan.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3358,6 +3358,23 @@ LinearScan::KillImplicitRegs(IR::Instr *instr)
33583358
this->RecordLoopUse(nullptr, LowererMDArch::GetRegIMulHighDestLower());
33593359
return;
33603360
}
3361+
3362+
if (instr->m_opcode == Js::OpCode::Yield)
3363+
{
3364+
#if defined(_M_X64)
3365+
RegNum regs[] = { RegRAX, RegRCX };
3366+
#else
3367+
RegNum regs[] = { RegEAX, RegECX };
3368+
#endif
3369+
for (int i = 0; i < 2; i++)
3370+
{
3371+
this->SpillReg(regs[i]);
3372+
this->tempRegs.Clear(regs[i]);
3373+
this->RecordLoopUse(nullptr, regs[i]);
3374+
}
3375+
3376+
return;
3377+
}
33613378
#endif
33623379

33633380
this->TrackInlineeArgLifetimes(instr);

lib/Backend/amd64/LinearScanMD.cpp

Lines changed: 60 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -517,35 +517,21 @@ IR::Instr* LinearScanMD::GeneratorBailIn::GenerateBailIn(IR::Instr* resumeLabelI
517517
instrAfter /* instrInsertRegSym */
518518
};
519519

520-
SaveInitializedRegister saveInitializedReg { false /* rax */, false /* rcx */ };
521-
522520
// 4) Restore symbols
523521
// - We don't need to restore argObjSyms because StackArgs is currently not enabled
524522
// Commented out here in case we do want to enable it in the future:
525523
// this->InsertRestoreSymbols(bailOutInfo->capturedValues->argObjSyms, insertionPoint, saveInitializedReg);
526524
//
527525
// - We move all argout symbols right before the call so we don't need to restore argouts either
528-
this->InsertRestoreSymbols(bailOutInfo->byteCodeUpwardExposedUsed, insertionPoint, saveInitializedReg);
526+
this->InsertRestoreSymbols(bailOutInfo->byteCodeUpwardExposedUsed, insertionPoint);
529527
Assert(!this->func->IsStackArgsEnabled());
530528

531-
// 5) Save/restore rax/rcx if needed
532-
if (saveInitializedReg.rax)
533-
{
534-
this->InsertSaveAndRestore(resumeLabelInstr, instrAfter, raxRegOpnd);
535-
}
536-
537-
if (saveInitializedReg.rcx)
538-
{
539-
this->InsertSaveAndRestore(resumeLabelInstr, instrAfter, rcxRegOpnd);
540-
}
541-
542529
return instrAfter;
543530
}
544531

545532
void LinearScanMD::GeneratorBailIn::InsertRestoreSymbols(
546533
BVSparse<JitArenaAllocator>* symbols,
547-
BailInInsertionPoint& insertionPoint,
548-
SaveInitializedRegister& saveInitializedReg
534+
BailInInsertionPoint& insertionPoint
549535
)
550536
{
551537
if (symbols == nullptr)
@@ -558,89 +544,77 @@ void LinearScanMD::GeneratorBailIn::InsertRestoreSymbols(
558544
StackSym* stackSym = this->func->m_symTable->FindStackSym(symId);
559545
Lifetime* lifetime = stackSym->scratch.linearScan.lifetime;
560546

561-
if (this->NeedsReloadingValueWhenBailIn(stackSym, lifetime))
547+
if (!this->NeedsReloadingValueWhenBailIn(stackSym, lifetime))
562548
{
563-
Js::RegSlot regSlot = stackSym->GetByteCodeRegSlot();
564-
IR::Opnd* srcOpnd = IR::IndirOpnd::New(
565-
this->raxRegOpnd,
566-
this->GetOffsetFromInterpreterStackFrame(regSlot),
567-
stackSym->GetType(),
568-
this->func
569-
);
570-
571-
if (lifetime->isSpilled)
549+
continue;
550+
}
551+
552+
Js::RegSlot regSlot = stackSym->GetByteCodeRegSlot();
553+
IR::Opnd* srcOpnd = IR::IndirOpnd::New(
554+
this->raxRegOpnd,
555+
this->GetOffsetFromInterpreterStackFrame(regSlot),
556+
stackSym->GetType(),
557+
this->func
558+
);
559+
560+
if (lifetime->isSpilled)
561+
{
562+
Assert(!stackSym->IsConst());
563+
// Stack restores require an extra register since we can't move an indir directly to an indir on amd64
564+
IR::SymOpnd* dstOpnd = IR::SymOpnd::New(stackSym, stackSym->GetType(), this->func);
565+
LinearScan::InsertMove(this->rcxRegOpnd, srcOpnd, insertionPoint.instrInsertStackSym);
566+
LinearScan::InsertMove(dstOpnd, this->rcxRegOpnd, insertionPoint.instrInsertStackSym);
567+
}
568+
else
569+
{
570+
// Register restores must come after stack restores so that we have RAX and RCX free to
571+
// use for stack restores and further RAX must be restored last since it holds the
572+
// pointer to the InterpreterStackFrame from which we are restoring values.
573+
// We must also track these restores using RecordDef in case the symbols are spilled.
574+
575+
IR::Instr* instr;
576+
577+
if (stackSym->IsConst())
572578
{
573-
Assert(!stackSym->IsConst());
574-
// Stack restores require an extra register since we can't move an indir directly to an indir on amd64
575-
IR::SymOpnd* dstOpnd = IR::SymOpnd::New(stackSym, stackSym->GetType(), this->func);
576-
LinearScan::InsertMove(this->rcxRegOpnd, srcOpnd, insertionPoint.instrInsertStackSym);
577-
LinearScan::InsertMove(dstOpnd, this->rcxRegOpnd, insertionPoint.instrInsertStackSym);
579+
instr = this->linearScanMD->linearScan->InsertLoad(insertionPoint.instrInsertRegSym, stackSym, lifetime->reg);
578580
}
579581
else
580582
{
581-
// Register restores must come after stack restores so that we have RAX and RCX free to
582-
// use for stack restores and further RAX must be restored last since it holds the
583-
// pointer to the InterpreterStackFrame from which we are restoring values.
584-
// We must also track these restores using RecordDef in case the symbols are spilled.
583+
IR::RegOpnd* dstRegOpnd = IR::RegOpnd::New(stackSym, stackSym->GetType(), this->func);
584+
dstRegOpnd->SetReg(lifetime->reg);
585+
instr = LinearScan::InsertMove(dstRegOpnd, srcOpnd, insertionPoint.instrInsertRegSym);
586+
}
585587

586-
IR::Instr* instr;
587-
588-
if (stackSym->IsConst())
589-
{
590-
instr = this->linearScanMD->linearScan->InsertLoad(insertionPoint.instrInsertRegSym, stackSym, lifetime->reg);
591-
}
592-
else
593-
{
594-
IR::RegOpnd* dstRegOpnd = IR::RegOpnd::New(stackSym, stackSym->GetType(), this->func);
595-
dstRegOpnd->SetReg(lifetime->reg);
596-
instr = LinearScan::InsertMove(dstRegOpnd, srcOpnd, insertionPoint.instrInsertRegSym);
597-
}
588+
if (insertionPoint.instrInsertRegSym == insertionPoint.instrInsertStackSym)
589+
{
590+
// This is the first register sym, make sure we don't insert stack stores
591+
// after this instruction so we can ensure rax and rcx remain free to use
592+
// for restoring spilled stack syms.
593+
insertionPoint.instrInsertStackSym = instr;
594+
}
598595

599-
if (insertionPoint.instrInsertRegSym == insertionPoint.instrInsertStackSym)
600-
{
601-
// This is the first register sym, make sure we don't insert stack stores
602-
// after this instruction so we can ensure rax and rcx remain free to use
603-
// for restoring spilled stack syms.
604-
insertionPoint.instrInsertStackSym = instr;
605-
}
596+
if (lifetime->reg == RegRAX)
597+
{
598+
// Ensure rax is restored last
599+
Assert(insertionPoint.instrInsertRegSym != insertionPoint.instrInsertStackSym);
606600

607-
if (lifetime->reg == RegRAX)
601+
insertionPoint.instrInsertRegSym = instr;
602+
603+
if (insertionPoint.raxRestoreInstr != nullptr)
608604
{
609-
// Ensure rax is restored last
610-
Assert(insertionPoint.instrInsertRegSym != insertionPoint.instrInsertStackSym);
611-
612-
insertionPoint.instrInsertRegSym = instr;
613-
614-
if (insertionPoint.raxRestoreInstr != nullptr)
615-
{
616-
AssertMsg(false, "this is unexpected until copy prop is enabled");
617-
// rax was mapped to multiple bytecode registers. Obviously only the first
618-
// restore we do will work so change all following stores to `mov rax, rax`.
619-
// We still need to keep them around for RecordDef in case the corresponding
620-
// dst sym is spilled later on.
621-
insertionPoint.raxRestoreInstr->FreeSrc1();
622-
insertionPoint.raxRestoreInstr->SetSrc1(this->raxRegOpnd);
623-
}
624-
625-
insertionPoint.raxRestoreInstr = instr;
605+
AssertMsg(false, "this is unexpected until copy prop is enabled");
606+
// rax was mapped to multiple bytecode registers. Obviously only the first
607+
// restore we do will work so change all following stores to `mov rax, rax`.
608+
// We still need to keep them around for RecordDef in case the corresponding
609+
// dst sym is spilled later on.
610+
insertionPoint.raxRestoreInstr->FreeSrc1();
611+
insertionPoint.raxRestoreInstr->SetSrc1(this->raxRegOpnd);
626612
}
627613

628-
this->linearScanMD->linearScan->RecordDef(lifetime, instr, 0);
629-
}
630-
}
631-
else
632-
{
633-
if (lifetime->reg == RegRAX)
634-
{
635-
Assert(!saveInitializedReg.rax);
636-
saveInitializedReg.rax = true;
614+
insertionPoint.raxRestoreInstr = instr;
637615
}
638616

639-
if (lifetime->reg == RegRCX)
640-
{
641-
Assert(!saveInitializedReg.rcx);
642-
saveInitializedReg.rcx = true;
643-
}
617+
this->linearScanMD->linearScan->RecordDef(lifetime, instr, 0);
644618
}
645619
}
646620
NEXT_BITSET_IN_SPARSEBV;
@@ -699,11 +673,3 @@ uint32 LinearScanMD::GeneratorBailIn::GetOffsetFromInterpreterStackFrame(Js::Reg
699673
return regSlot * sizeof(Js::Var) + Js::InterpreterStackFrame::GetOffsetOfLocals();
700674
}
701675
}
702-
703-
void LinearScanMD::GeneratorBailIn::InsertSaveAndRestore(IR::Instr* start, IR::Instr* end, IR::RegOpnd* reg)
704-
{
705-
IR::Instr* push = IR::Instr::New(Js::OpCode::PUSH, nullptr /* dst */, reg /* src1 */, this->func);
706-
IR::Instr* pop = IR::Instr::New(Js::OpCode::POP, reg /* dst */, this->func);
707-
start->InsertAfter(push);
708-
end->InsertBefore(pop);
709-
}

lib/Backend/amd64/LinearScanMD.h

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -88,17 +88,6 @@ class LinearScanMD : public LinearScanMDShared
8888
IR::Instr* instrInsertRegSym;
8989
};
9090

91-
// There are symbols that we don't need to restore such as constant values,
92-
// ScriptFunction's Environment (through LdEnv) and the address pointing to for-in enumerator
93-
// on the interpreter frame because their values are already loaded before (or as part) of the
94-
// generator resume jump table. In such cases, they could already be in either rax or rcx.
95-
// So we would need to save their values (and restore afterwards) before generating the bail-in code.
96-
struct SaveInitializedRegister
97-
{
98-
bool rax;
99-
bool rcx;
100-
};
101-
10291
Func* const func;
10392
LinearScanMD* const linearScanMD;
10493
const JITTimeFunctionBody* const jitFnBody;
@@ -110,13 +99,7 @@ class LinearScanMD : public LinearScanMDShared
11099
uint32 GetOffsetFromInterpreterStackFrame(Js::RegSlot regSlot) const;
111100
IR::SymOpnd* CreateGeneratorObjectOpnd() const;
112101

113-
void InsertSaveAndRestore(IR::Instr* start, IR::Instr* end, IR::RegOpnd* reg);
114-
115-
void InsertRestoreSymbols(
116-
BVSparse<JitArenaAllocator>* symbols,
117-
BailInInsertionPoint& insertionPoint,
118-
SaveInitializedRegister& saveInitializedReg
119-
);
102+
void InsertRestoreSymbols(BVSparse<JitArenaAllocator>* symbols, BailInInsertionPoint& insertionPoint);
120103

121104
public:
122105
GeneratorBailIn(Func* func, LinearScanMD* linearScanMD);

0 commit comments

Comments
 (0)