Index: lib/Target/X86/X86InstrInfo.h =================================================================== --- lib/Target/X86/X86InstrInfo.h +++ lib/Target/X86/X86InstrInfo.h @@ -545,12 +545,33 @@ bool isTailCall(const MachineInstr &Inst) const override; + /// \brief Represents the type of fixup that should be done to an instruction + /// if one is available. + /// \p NotFixable instructions have no fixup. + /// \p FixOp0 instructions have the stack pointer as operand 0, and can be + /// fixed by adding 8 to their displacement. + /// \p FixOp5 instructions have the stack pointer as operand 5, and can be + /// fixed by adding 8 to their displacement. + enum MachineOutlinerFixupType { + NotFixable, + FixOp0, + FixOp5 + }; + unsigned getOutliningBenefit(size_t SequenceSize, size_t Occurrences, bool CanBeTailCall) const override; bool isFunctionSafeToOutlineFrom(MachineFunction &MF) const override; + /// \brief Return the type of fixup that an instruction would take to be valid + /// post-outlining if possible. Return NotFixable if no fixup is available. + MachineOutlinerFixupType getPostOutliningFixup(MachineInstr &MI) const; + + /// \brief Fix up outlined instructions that used the stack pointer in an + /// outlined function \p MF. + void fixupPostOutline(MachineFunction &MF) const; + llvm::X86GenInstrInfo::MachineOutlinerInstrType getOutliningType(MachineInstr &MI) const override; Index: lib/Target/X86/X86InstrInfo.cpp =================================================================== --- lib/Target/X86/X86InstrInfo.cpp +++ lib/Target/X86/X86InstrInfo.cpp @@ -10409,6 +10409,27 @@ return MF.getFunction()->hasFnAttribute(Attribute::NoRedZone); } +X86InstrInfo::MachineOutlinerFixupType +X86InstrInfo::getPostOutliningFixup(MachineInstr &MI) const { + if (!isFrameStoreOpcode(MI.getOpcode()) && !isFrameLoadOpcode(MI.getOpcode())) + return MachineOutlinerFixupType::NotFixable; + + switch (MI.getOpcode()) { + case X86::MOV64mr: + return MI.getOperand(0).getReg() == X86::RSP ? + MachineOutlinerFixupType::FixOp0 : + MachineOutlinerFixupType::NotFixable; + case X86::MOV64rm: + return MI.getOperand(5).getReg() == X86::RSP ? + MachineOutlinerFixupType::FixOp5 : + MachineOutlinerFixupType::NotFixable; + default: + break; + } + + return MachineOutlinerFixupType::NotFixable; +} + X86GenInstrInfo::MachineOutlinerInstrType X86InstrInfo::getOutliningType(MachineInstr &MI) const { @@ -10431,20 +10452,6 @@ return MachineOutlinerInstrType::Illegal; } - // Don't outline anything that modifies or reads from the stack pointer. - // - // FIXME: There are instructions which are being manually built without - // explicit uses/defs so we also have to check the MCInstrDesc. We should be - // able to remove the extra checks once those are fixed up. For example, - // sometimes we might get something like %RAX = POP64r 1. This won't be - // caught by modifiesRegister or readsRegister even though the instruction - // really ought to be formed so that modifiesRegister/readsRegister would - // catch it. - if (MI.modifiesRegister(X86::RSP, &RI) || MI.readsRegister(X86::RSP, &RI) || - MI.getDesc().hasImplicitUseOfPhysReg(X86::RSP) || - MI.getDesc().hasImplicitDefOfPhysReg(X86::RSP)) - return MachineOutlinerInstrType::Illegal; - // Outlined calls change the instruction pointer, so don't read from it. if (MI.readsRegister(X86::RIP, &RI) || MI.getDesc().hasImplicitUseOfPhysReg(X86::RIP) || @@ -10461,13 +10468,37 @@ MOP.isTargetIndex()) return MachineOutlinerInstrType::Illegal; + // Does this instruction modify the stack pointer? + // + // FIXME: There are instructions which are being manually built without + // explicit uses/defs so we also have to check the MCInstrDesc. We should be + // able to remove the extra checks once those are fixed up. For example, + // sometimes we might get something like %RAX = POP64r 1. This won't be + // caught by modifiesRegister or readsRegister even though the instruction + // really ought to be formed so that modifiesRegister/readsRegister would + // catch it. + if (MI.modifiesRegister(X86::RSP, &RI) || + MI.readsRegister(X86::RSP, &RI) || + MI.getDesc().hasImplicitUseOfPhysReg(X86::RSP) || + MI.getDesc().hasImplicitDefOfPhysReg(X86::RSP)) { + + // Can we transform this instruction post-outlining so that it will be + // valid? + if (getPostOutliningFixup(MI) != MachineOutlinerFixupType::NotFixable) { + // Yes, so return that we can do so. + return MachineOutlinerInstrType::Legal; + } else { + // No, so return that it's illegal. + return MachineOutlinerInstrType::Illegal; + } + } + return MachineOutlinerInstrType::Legal; } void X86InstrInfo::insertOutlinerEpilogue(MachineBasicBlock &MBB, MachineFunction &MF, bool IsTailCall) const { - // If we're a tail call, we already have a return, so don't do anything. if (IsTailCall) return; @@ -10476,13 +10507,38 @@ // Add it in. MachineInstr *retq = BuildMI(MF, DebugLoc(), get(X86::RETQ)); MBB.insert(MBB.end(), retq); + + // Perform any necessary fixups on the outlined function. + fixupPostOutline(MF); +} + +void X86InstrInfo::fixupPostOutline(MachineFunction &MF) const { + for (MachineBasicBlock &MBB: MF) { + // If any instruction is something we promised we could fix, fix it. + for (MachineInstr &MI: MBB) { + switch(getPostOutliningFixup(MI)) { + case MachineOutlinerFixupType::NotFixable: + break; + case MachineOutlinerFixupType::FixOp0 : { + auto &Disp = MI.getOperand(X86::AddrDisp); + int64_t oldDispVal = Disp.getImm(); + Disp.setImm(oldDispVal + 8); + break; + } + case MachineOutlinerFixupType::FixOp5: { + auto &Disp = MI.getOperand(5 + X86::AddrDisp); + int64_t oldDispVal = Disp.getImm(); + Disp.setImm(oldDispVal + 8); + break; + } + } + } + } } void X86InstrInfo::insertOutlinerPrologue(MachineBasicBlock &MBB, MachineFunction &MF, - bool IsTailCall) const { - return; -} + bool IsTailCall) const {} MachineBasicBlock::iterator X86InstrInfo::insertOutlinedCall(Module &M, MachineBasicBlock &MBB,