void handleCalleeSaves(Code& code)
{
    PhaseScope phaseScope(code, "handleCalleeSaves");

    RegisterSet usedCalleeSaves;

    for (BasicBlock* block : code) {
        for (Inst& inst : *block) {
            inst.forEachTmpFast(
                [&] (Tmp& tmp) {
                    // At first we just record all used regs.
                    usedCalleeSaves.set(tmp.reg());
                });

            if (inst.hasSpecial())
                usedCalleeSaves.merge(inst.extraClobberedRegs());
        }
    }

    // Now we filter to really get the callee saves.
    usedCalleeSaves.filter(RegisterSet::calleeSaveRegisters());
    usedCalleeSaves.exclude(RegisterSet::stackRegisters()); // We don't need to save FP here.

    if (!usedCalleeSaves.numberOfSetRegisters())
        return;

    code.calleeSaveRegisters() = RegisterAtOffsetList(usedCalleeSaves);

    size_t byteSize = 0;
    for (const RegisterAtOffset& entry : code.calleeSaveRegisters())
        byteSize = std::max(static_cast<size_t>(-entry.offset()), byteSize);

    StackSlot* savesArea = code.addStackSlot(byteSize, StackSlotKind::Locked);
    // This is a bit weird since we could have already pinned a different stack slot to this
    // area. Also, our runtime does not require us to pin the saves area. Maybe we shouldn't pin it?
    savesArea->setOffsetFromFP(-byteSize);

    auto argFor = [&] (const RegisterAtOffset& entry) -> Arg {
        return Arg::stack(savesArea, entry.offset() + byteSize);
    };

    InsertionSet insertionSet(code);
    
    // First insert saving code in the prologue.
    for (const RegisterAtOffset& entry : code.calleeSaveRegisters()) {
        insertionSet.insert(
            0, entry.reg().isGPR() ? Move : MoveDouble, code[0]->at(0).origin,
            Tmp(entry.reg()), argFor(entry));
    }
    insertionSet.execute(code[0]);

    // Now insert restore code at epilogues.
    for (BasicBlock* block : code) {
        Inst& last = block->last();
        if (!isReturn(last.opcode))
            continue;

        for (const RegisterAtOffset& entry : code.calleeSaveRegisters()) {
            insertionSet.insert(
                block->size() - 1, entry.reg().isGPR() ? Move : MoveDouble, last.origin,
                argFor(entry), Tmp(entry.reg()));
        }
        insertionSet.execute(block);
    }
}