Index: include/llvm/CodeGen/Passes.h =================================================================== --- include/llvm/CodeGen/Passes.h +++ include/llvm/CodeGen/Passes.h @@ -397,6 +397,10 @@ /// This pass frees the memory occupied by the MachineFunction. FunctionPass *createFreeMachineFunctionPass(); + + /// This pass performs outlining on machine instructions directly before printing assembly. + ModulePass *createOutlinerPass(); + } // End llvm namespace /// Target machine pass initializer for passes with dependencies. Use with Index: include/llvm/Target/TargetInstrInfo.h =================================================================== --- include/llvm/Target/TargetInstrInfo.h +++ include/llvm/Target/TargetInstrInfo.h @@ -1496,6 +1496,46 @@ unsigned CallFrameSetupOpcode, CallFrameDestroyOpcode; unsigned CatchRetOpcode; unsigned ReturnOpcode; + +public: + /// isLegalToOutline - Return true if the instruction is legal to outline. + virtual bool isLegalToOutline(const MachineInstr &MI) const { + llvm_unreachable( + "Target didn't implement TargetInstrInfo::isLegalToOutline!"); + } + + /// insertOutlinerEpilog - Insert a custom epilogue for outlined functions. + /// This may be empty, in which case no epilogue or return statement will be + /// emitted. + virtual void insertOutlinerEpilog(MachineBasicBlock *MBB, + MachineFunction &MF) const { + return; + } + + /// insertOutlinedCall - Insert a call to an outlined function into the + /// program. Returns an iterator to the spot where we inserted the call. This + /// must be implemented + /// by the target. + virtual MachineBasicBlock::instr_iterator + insertOutlinedCall(MachineBasicBlock *MBB, + MachineBasicBlock::instr_iterator &It, MachineFunction *MF, + MCSymbol *Name) const { + llvm_unreachable( + "Target didn't implement TargetInstrInfo::insertOutlinedCall!"); + } + + /// insertOutlinerProlog - Insert a custom prologue for outlined functions. + /// This may be empty, in which case no prologue will be emitted. + virtual void insertOutlinerProlog(MachineBasicBlock *MBB, + MachineFunction &MF) const { + return; + } + + /// functionIsSafeToOutlineFrom - Return true if the function can safely be + /// outlined from. By default, this means that the function has no red zone. + virtual bool functionIsSafeToOutlineFrom(Function &F) const { + return F.hasFnAttribute(Attribute::NoRedZone); + } }; /// \brief Provide DenseMapInfo for TargetInstrInfo::RegSubRegPair. Index: lib/CodeGen/CMakeLists.txt =================================================================== --- lib/CodeGen/CMakeLists.txt +++ lib/CodeGen/CMakeLists.txt @@ -141,6 +141,7 @@ VirtRegMap.cpp WinEHPrepare.cpp XRayInstrumentation.cpp + MachineOutliner.cpp ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/CodeGen Index: lib/CodeGen/MachineOutliner.h =================================================================== --- /dev/null +++ lib/CodeGen/MachineOutliner.h @@ -0,0 +1,156 @@ +//===---- MachineOutliner.h - Outline instructions -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// The MachineOutliner is a code size reduction pass. It finds repeated +// sequences of instructions and pulls them out into their own functions. +// By pulling out such repeated sequences, we can reduce code size. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_CODEGEN_MACHINEOUTLINER_H +#define LLVM_LIB_CODEGEN_MACHINEOUTLINER_H + +#define DEBUG_TYPE "machine-outliner" + +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/SuffixTree.h" +#include "llvm/ADT/Twine.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Target/TargetSubtargetInfo.h" +#include + +typedef size_t CharacterType; +typedef std::vector ContainerType; +typedef TerminatedString String; +typedef TerminatedStringList StringCollection; +typedef SuffixTree STree; + +/// Helper struct that stores the basic block, the function, the string, and +/// location of a Candidate. +struct Candidate { + MachineBasicBlock *BB; // BB containing this Candidate + MachineFunction *ParentMF; // Function containing bb + String *Str; // The actual string to outline + size_t Length; // str->length() + size_t StartIdxInBB; // Start index in the string + size_t EndIdxInBB; // End index in the string + size_t FunctionIdx; // Index of the candidate's function in the function list + + Candidate(MachineBasicBlock *bb_, MachineFunction *bb_BBParent_, String *Str_, + const size_t &Length_, const size_t &StartIdxInBB_, + const size_t &EndIdxInBB_, const size_t &fn_Id_) + : BB(bb_), ParentMF(bb_BBParent_), Str(Str_), Length(Length_), + StartIdxInBB(StartIdxInBB_), EndIdxInBB(EndIdxInBB_), + FunctionIdx(fn_Id_) {} + + bool operator<(const Candidate &rhs) const { + return StartIdxInBB < rhs.StartIdxInBB; + } +}; + +/// Output for candidates for debugging purposes. +raw_ostream &operator<<(raw_ostream &os, const Candidate &c) { + os << *(c.Str) << "\n"; + os << "StartIdxInBB: " << c.StartIdxInBB << "\n"; + os << "EndIdxInBB: " << c.EndIdxInBB << "\n"; + return os; +} + +/// Helper struct that stores information about an actual outlined function. +struct OutlinedFunction { + MachineFunction *MF; // The actual outlined function + MachineBasicBlock *OccBB; // The FIRST occurrence of its string + MachineFunction *BBParent; // The BBParent of OccBB + size_t IdxInSC; // The start index in the string. + size_t StartIdxInBB; // The start index in OccBB. + size_t EndIdxInBB; // The end index in OccBB. + size_t Name; // The name of this function in the program. + size_t Id; // The ID of this function in the proxy string. + size_t OccurrenceCount; // Number of times this function appeared. + + OutlinedFunction(MachineBasicBlock *OccBB_, MachineFunction *BBParent_, + const size_t &IdxInSC_, const size_t &length_, + const size_t &StartIdxInBB_, const size_t &EndIdxInBB_, + const size_t &Name_, const size_t &Id_, + const size_t &OccurrenceCount_) + : OccBB(OccBB_), BBParent(BBParent_), IdxInSC(IdxInSC_), + StartIdxInBB(StartIdxInBB_), EndIdxInBB(EndIdxInBB_), Name(Name_), + Id(Id_), OccurrenceCount(OccurrenceCount_) {} +}; + +namespace llvm { +struct MachineOutliner : public ModulePass { + static char ID; + + DenseMap + InstructionIntegerMap; + STree *ST = nullptr; + + // Target information + size_t FunctionCallOverhead; // TODO + int CurrIllegalInstrMapping; + int CurrLegalInstrMapping; + size_t CurrentFunctionID; + std::vector *FunctionNames; // FIXME: Release function names. + + bool runOnModule(Module &M) override; + StringRef getPassName() const override { return "Outliner"; } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.addPreserved(); + AU.setPreservesAll(); + ModulePass::getAnalysisUsage(AU); + } + + MachineOutliner() : ModulePass(ID) { + ST = new STree(); + + // FIXME: Release function names + FunctionNames = new std::vector; + } + + // General outlining functions. + void buildProxyString(ContainerType &Container, MachineBasicBlock *BB, + const TargetRegisterInfo *TRI, + const TargetInstrInfo *TII); + bool outline(Module &M, std::vector &Worklist, + std::vector &CandidateList, + std::vector &FunctionList); + size_t removeOutsideSameBB(std::vector> &occ, + const size_t &length, StringCollection &sc); + MachineFunction *createOutlinedFunction(Module &M, + const OutlinedFunction &OF); + void buildCandidateList(std::vector &CandidateList, + std::vector &FunctionList, + std::vector &Worklist); +}; + +// FIXME: Free after printing +std::vector *OutlinerFunctionNames; +ModulePass *createOutlinerPass() { + MachineOutliner *OL = new MachineOutliner(); + OutlinerFunctionNames = OL->FunctionNames; + return OL; +} + +} // LLVM namespace + + +#endif //LLVM_LIB_CODEGEN_MACHINEOUTLINER_H Index: lib/CodeGen/MachineOutliner.cpp =================================================================== --- /dev/null +++ lib/CodeGen/MachineOutliner.cpp @@ -0,0 +1,350 @@ +//===---- MachineOutliner.cpp - Outline instructions -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementation of MachineOutliner.h +// +//===----------------------------------------------------------------------===// + +#include "MachineOutliner.h" + +STATISTIC(NumOutlinedStat, "Number of candidates outlined"); +STATISTIC(FunctionsCreatedStat, "Number of functions created"); + +using namespace llvm; + +char MachineOutliner::ID = 0; + +/// Construct a proxy string for a MachineBasicBlock. +void MachineOutliner::buildProxyString(ContainerType &Container, + MachineBasicBlock *BB, + const TargetRegisterInfo *TRI, + const TargetInstrInfo *TII) { + for (auto BBI = BB->instr_begin(), BBE = BB->instr_end(); BBI != BBE; BBI++) { + + // First, check if the current instruction is legal to outline at all + bool IsSafeToOutline = TII->isLegalToOutline(*BBI); + + // If it's not, give it a bad number + if (!IsSafeToOutline) { + Container.push_back(CurrIllegalInstrMapping); + CurrIllegalInstrMapping--; + } + + // If it is legal, we either insert it size_to the map, or get its existing + // Id + else { + auto Mapping = InstructionIntegerMap.find(&*BBI); + + // It was found in the map... + if (Mapping != InstructionIntegerMap.end()) { + Container.push_back(Mapping->second); + } + + // Otherwise, it wasn't there, so we should put it there! + else { + InstructionIntegerMap.insert( + std::pair(&*BBI, CurrLegalInstrMapping)); + Container.push_back(CurrLegalInstrMapping); + CurrLegalInstrMapping++; + CurrentFunctionID++; + } + } + } +} + +/// Remove candidates which don't lie within the same MachineBasicBlock. +size_t MachineOutliner::removeOutsideSameBB( + std::vector> &Occurrences, const size_t &Length, + StringCollection &SC) { + size_t Removed = 0; + + // StringLocation: first = index of the string, second = index size_to that + // string. + for (size_t i = 0, e = Occurrences.size(); i < e; i++) { + auto StringLocation = SC.stringIndexContaining(Occurrences[i].second); + if (StringLocation.second + Length - 1 > + SC.stringAt(StringLocation.first).size()) { + Occurrences.erase(Occurrences.begin() + i); + Removed++; + } + } + + return Removed; +} + +/// Find the potential outlining candidates for the program and return them in +/// CandidateList. +void MachineOutliner::buildCandidateList( + std::vector &CandidateList, + std::vector &FunctionList, + std::vector &Worklist) { + + String *CandidateString = ST->longestRepeatedSubstring(); + + // FIXME: That 2 should be a target-dependent minimum length. + if (CandidateString != nullptr && CandidateString->length() >= 2) { + size_t FunctionsCreated = 0; + StringCollection SC = ST->SC; + std::vector> *Occurrences = + ST->findOccurrences(*CandidateString); + + // Query the tree for candidates until we run out of candidates to outline. + do { + assert(Occurrences != nullptr && + "Null occurrences for longestRepeatedSubstring!"); + removeOutsideSameBB(*Occurrences, CandidateString->length(), SC); + + // If there are at least two occurrences of this candidate, then we should + // make it a function and keep track of it. + if (Occurrences->size() >= 2) { + auto FirstOcc = (*Occurrences)[0]; + size_t IdxInSC = FirstOcc.second; + auto StringLocation = ST->SC.stringIndexContaining(IdxInSC); + size_t StartIdxInBB = StringLocation.second; + size_t EndIdxInBB = StartIdxInBB + CandidateString->length() - 1; + MachineBasicBlock *OccBB = Worklist[StringLocation.first]; + MachineFunction *BBParent = OccBB->getParent(); + + FunctionList.push_back(OutlinedFunction( + OccBB, BBParent, IdxInSC, CandidateString->length() - 1, + StartIdxInBB, EndIdxInBB, FunctionsCreated, CurrentFunctionID, + Occurrences->size())); + + // Save each of the occurrences for the outlining process. + for (auto &Occ : *Occurrences) + CandidateList.push_back(Candidate( + OccBB, BBParent, CandidateString, CandidateString->length(), + Occ.second, Occ.second + CandidateString->length(), + FunctionsCreated)); + + CurrentFunctionID++; + FunctionsCreated++; + FunctionsCreatedStat++; + } + + // Find the next candidate and continue the process. + CandidateString = ST->longestRepeatedSubstring(); + } while (CandidateString && CandidateString->length() >= 2 && + (Occurrences = ST->findOccurrences(*CandidateString))); + + std::sort(CandidateList.begin(), CandidateList.end()); + + DEBUG(for (size_t i = 0, e = CandidateList.size(); i < e; i++) { + dbgs() << "Candidate " << i << ": \n"; + dbgs() << CandidateList[i] << "\n"; + }); + } +} + +/// Create a new Function and MachineFunction for the OutlinedFunction OF. Place +/// that function in M. +MachineFunction * +MachineOutliner::createOutlinedFunction(Module &M, const OutlinedFunction &OF) { + + // Create the function name and store it size_to the function list. + std::ostringstream NameStream; + NameStream << "OUTLINED_FUNCTION" << OF.Name; + std::string *Name = new std::string(NameStream.str()); + FunctionNames->push_back(Name); + + // Create the function using an IR-level function. + LLVMContext &C = M.getContext(); + Function *F = dyn_cast( + M.getOrInsertFunction(Name->c_str(), Type::getVoidTy(C), NULL)); + assert(F != nullptr); + F->setLinkage(GlobalValue::PrivateLinkage); + + BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F); + IRBuilder<> Builder(EntryBB); + Builder.CreateRetVoid(); + + MachineModuleInfo &MMI = getAnalysis(); + MachineFunction &MF = MMI.getMachineFunction(*F); + MachineBasicBlock *MBB = MF.CreateMachineBasicBlock(); + const TargetSubtargetInfo *target = &(MF.getSubtarget()); + const TargetInstrInfo *TII = target->getInstrInfo(); + + /// Find where the occurrence we want to copy starts and ends. + DEBUG(dbgs() << "OF.StartIdxInBB = " << OF.StartIdxInBB << "\n"; + dbgs() << "OF.EndIdxInBB = " << OF.EndIdxInBB << "\n";); + + size_t i; + auto StartIt = OF.OccBB->instr_begin(); + + for (i = 0; i < OF.StartIdxInBB; i++) + ++StartIt; + + auto EndIt = StartIt; + + for (; i < OF.EndIdxInBB; ++i) + ++EndIt; + + /// Insert the instructions from the candidate size_to the function, along + /// with + /// the special epilogue and prologue for the outliner. + MF.insert(MF.begin(), MBB); + TII->insertOutlinerEpilog(MBB, MF); + + MachineInstr *MI; + + // Clone each machine instruction in the outlined range and insert them before + // the inserted epilogue. + while (EndIt != StartIt) { + MI = MF.CloneMachineInstr(&*EndIt); + MI->dropMemRefs(); + MBB->insert(MBB->instr_begin(), MI); + EndIt--; + } + + MI = MF.CloneMachineInstr(&*EndIt); + MI->dropMemRefs(); + MBB->insert(MBB->instr_begin(), MI); + + TII->insertOutlinerProlog(MBB, MF); + + DEBUG(dbgs() << "New function: \n"; dbgs() << *Name << ":\n"; + for (auto MBB = MF.begin(), EBB = MF.end(); MBB != EBB; + MBB++) { (&(*MBB))->dump(); }); + + return &MF; +} + +/// Find outlining candidates, create functions from them, and replace them with +/// function calls. +bool MachineOutliner::outline(Module &M, + std::vector &Worklist, + std::vector &CandidateList, + std::vector &FunctionList) { + StringCollection SC = ST->SC; + bool OutlinedSomething = false; + int Offset = 0; + + for (size_t i = 0, e = FunctionList.size(); i < e; i++) { + OutlinedFunction OF = FunctionList[i]; + FunctionList[i].MF = createOutlinedFunction(M, OF); + } + + /// Replace the candidates with calls to their respective outlined functions. + for (const Candidate &C : CandidateList) { + size_t OffsetedStringStart = C.StartIdxInBB + Offset; + size_t OffsetedStringEnd = OffsetedStringStart + C.Length; + + /// If this spot doesn't match with our string, we must have already + /// outlined something from here. Therefore, we should skip it to avoid + /// overlaps. + + // If the offsetted string starts below index 0, we must have overlapped + // something + bool AlreadyOutlinedFrom = (OffsetedStringStart > OffsetedStringEnd); + + if (!AlreadyOutlinedFrom) { + size_t j = 0; + for (size_t i = OffsetedStringStart; i < OffsetedStringEnd; i++) { + if (SC[i] != (*(C.Str))[j]) { + FunctionList[C.FunctionIdx].OccurrenceCount--; + AlreadyOutlinedFrom = true; + break; + } + j++; + } + } + + if (AlreadyOutlinedFrom || FunctionList[C.FunctionIdx].OccurrenceCount < 2) + continue; + + /// We have a candidate which doesn't conflict with any other candidates, so + /// we can go ahead and outline it. + OutlinedSomething = true; + auto StringLocation = SC.stringIndexContaining(OffsetedStringStart); + NumOutlinedStat++; + + /// Update the proxy string. + SC.insertBefore(OffsetedStringStart, FunctionList[C.FunctionIdx].Id); + + SC.erase(OffsetedStringStart + 1, OffsetedStringEnd + 1); + + /// Update the module. + MachineFunction *MF = FunctionList[C.FunctionIdx].MF; + MachineBasicBlock *MBB = Worklist[StringLocation.first]; + const TargetSubtargetInfo *target = &(MF->getSubtarget()); + const TargetInstrInfo *TII = target->getInstrInfo(); + + /// Get the name of the function we want to insert a call to. + MCContext &Ctx = MF->getContext(); + Twine size_ternalName = Twine("l_", MF->getName()); + MCSymbol *Name = Ctx.getOrCreateSymbol(size_ternalName); + + /// Find the start of the candidate's range, insert the call before it, and + /// then delete the range. + size_t i; + auto It = MBB->instr_begin(); + auto StartIt = It; + auto EndIt = It; + + for (i = 0; i < StringLocation.second; ++i) { + ++StartIt; + ++It; + } + + StartIt = TII->insertOutlinedCall(MBB, StartIt, MF, Name); + ++Offset; // Inserted one character => everything shifts right by 1. + ++StartIt; + + for (; i < StringLocation.second + C.Length; ++i) + ++It; + + EndIt = It; + + MBB->erase(StartIt, EndIt); + Offset -= C.Length; + } + + return OutlinedSomething; +} + +/// Construct the suffix tree for the program and run the outlining algorithm. +bool MachineOutliner::runOnModule(Module &M) { + MachineModuleInfo &MMI = getAnalysis(); + std::vector Worklist; + + CurrIllegalInstrMapping = -1; + CurrLegalInstrMapping = 0; + + // Set up the suffix tree. + for (auto MI = M.begin(), ME = M.end(); MI != ME; MI++) { + Function *F = &*MI; + MachineFunction &MF = MMI.getMachineFunction(*F); + const TargetSubtargetInfo *target = &(MF.getSubtarget()); + const TargetRegisterInfo *TRI = target->getRegisterInfo(); + const TargetInstrInfo *TII = target->getInstrInfo(); + + if (F->empty() || !TII->functionIsSafeToOutlineFrom(*F)) + continue; + + for (auto MFI = MF.begin(), MFE = MF.end(); MFI != MFE; ++MFI) { + MachineBasicBlock *MBB = &*MFI; + Worklist.push_back(MBB); + ContainerType Container; + buildProxyString(Container, MBB, TRI, TII); + String *BBString = new String(Container); + ST->append(BBString); + } + } + // Find all of the candidates for outlining. + bool OutlinedSomething = false; + std::vector CandidateList; + std::vector FunctionList; + + CurrentFunctionID = InstructionIntegerMap.size(); + buildCandidateList(CandidateList, FunctionList, Worklist); + OutlinedSomething = outline(M, Worklist, CandidateList, FunctionList); + + delete ST; + return OutlinedSomething; +} Index: lib/CodeGen/TargetPassConfig.cpp =================================================================== --- lib/CodeGen/TargetPassConfig.cpp +++ lib/CodeGen/TargetPassConfig.cpp @@ -92,6 +92,8 @@ cl::desc("Verify generated machine code"), cl::init(false), cl::ZeroOrMore); +static cl::opt EnableMIROutliner("enable-machine-outliner", cl::Hidden, + cl::desc("Enable machine outliner")); static cl::opt PrintMachineInstrs("print-machineinstrs", cl::ValueOptional, @@ -128,7 +130,7 @@ "Enable unification-based CFL-AA"), clEnumValN(CFLAAType::Andersen, "anders", "Enable inclusion-based CFL-AA"), - clEnumValN(CFLAAType::Both, "both", + clEnumValN(CFLAAType::Both, "both", "Enable both variants of CFL-AA"))); /// Allow standard passes to be disabled by command line options. This supports @@ -671,6 +673,9 @@ addPass(&XRayInstrumentationID, false); addPass(&PatchableFunctionID, false); + if (EnableMIROutliner) + PM->add(createOutlinerPass()); + AddingMachinePasses = false; } Index: lib/Target/X86/X86InstrInfo.h =================================================================== --- lib/Target/X86/X86InstrInfo.h +++ lib/Target/X86/X86InstrInfo.h @@ -579,6 +579,20 @@ bool isFrameOperand(const MachineInstr &MI, unsigned int Op, int &FrameIndex) const; +public: + /// Returns true if a MachineInstr is safe to outline. + bool isLegalToOutline(const MachineInstr &MI) const override; + + /// Inserts the custom outliner epilogue for an outlined function. + void insertOutlinerEpilog(MachineBasicBlock *MBB, + MachineFunction &MF) const override; + + /// Inserts a call to an outlined function into an existing MachineBasicBlock. + MachineBasicBlock::instr_iterator + insertOutlinedCall(MachineBasicBlock *MBB, + MachineBasicBlock::instr_iterator &It, MachineFunction *MF, + MCSymbol *Name) const override; + /// Returns true iff the routine could find two commutable operands in the /// given machine instruction with 3 vector inputs. /// The 'SrcOpIdx1' and 'SrcOpIdx2' are INPUT and OUTPUT arguments. Their Index: lib/Target/X86/X86InstrInfo.cpp =================================================================== --- lib/Target/X86/X86InstrInfo.cpp +++ lib/Target/X86/X86InstrInfo.cpp @@ -8926,3 +8926,67 @@ char LDTLSCleanup::ID = 0; FunctionPass* llvm::createCleanupLocalDynamicTLSPass() { return new LDTLSCleanup(); } + +bool X86InstrInfo::isLegalToOutline(const MachineInstr &MI) const { + int Dummy; + + // Don't outline returns or basic block terminators. + if (MI.isReturn() || MI.isTerminator()) + return false; + + // Don't outline anything that modifies or reads from the stack pointer. + else if (MI.modifiesRegister(X86::RSP, &RI) || + MI.readsRegister(X86::RSP, &RI)) + return false; + + else if (MI.modifiesRegister(X86::RIP, &RI) || + MI.readsRegister(X86::RIP, &RI)) + return false; + + // Don't outline the frame setup or destroy for a function + else if (MI.getFlag(MachineInstr::MIFlag::FrameSetup) || + MI.getFlag(MachineInstr::MIFlag::FrameDestroy)) + return false; + + else if (MI.isCFIInstruction()) + return false; + + else if (isLoadFromStackSlot(MI, Dummy) || isStoreToStackSlot(MI, Dummy)) + return false; + + else if (isLoadFromStackSlotPostFE(MI, Dummy) || + isStoreToStackSlotPostFE(MI, Dummy)) + return false; + + else if (MI.isLabel()) + return false; + + // Check if the outliner has any CPI junk-- we can't move around stuff + // which depends on the offsets between two instructions + else { + for (auto It = MI.operands_begin(), Et = MI.operands_end(); It != Et; + It++) { + if ((*It).isCPI() || (*It).isJTI() || (*It).isCFIIndex() || + (*It).isFI() || (*It).isTargetIndex()) { + return false; + } + } + } + + return true; +} + +void X86InstrInfo::insertOutlinerEpilog(MachineBasicBlock *MBB, + MachineFunction &MF) const { + MachineInstr *retq = BuildMI(MF, DebugLoc(), get(X86::RETQ)); + MBB->insert(MBB->instr_begin(), retq); +} + +MachineBasicBlock::instr_iterator +X86InstrInfo::insertOutlinedCall(MachineBasicBlock *MBB, + MachineBasicBlock::instr_iterator &It, + MachineFunction *MF, MCSymbol *Name) const { + It = MBB->insert( + It, BuildMI(*MF, DebugLoc(), get(X86::CALL64pcrel32)).addSym(Name)); + return It; +} Index: test/CodeGen/X86/machineoutliner.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/machineoutliner.ll @@ -0,0 +1,47 @@ +; RUN: llc -enable-machine-outliner -march=x86-64 < %s | FileCheck %s +; Test that the outliner can outline a simple function. + +; Function Attrs: noredzone nounwind ssp uwtable +define void @foo() #0 { +entry: + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %z = alloca i32, align 4 + store i32 1, i32* %x, align 4 + store i32 2, i32* %y, align 4 + store i32 3, i32* %z, align 4 + ret void + + ; CHECK: subq $12, %rsp + ; CHECK: callq l_OUTLINED_FUNCTION0 + ; CHECK: addq $12, %rsp +} + +; Function Attrs: noredzone nounwind ssp uwtable +define i32 @main() #0 { +entry: + %retval = alloca i32, align 4 + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %z = alloca i32, align 4 + store i32 0, i32* %retval, align 4 + store i32 1, i32* %x, align 4 + store i32 2, i32* %y, align 4 + store i32 3, i32* %z, align 4 + ret i32 0 + + ; CHECK: movl $0, -16(%rbp) + ; CHECK: callq l_OUTLINED_FUNCTION0 + ; CHECK: xorl %eax, %eax + +} + +attributes #0 = { noredzone nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } + +; CHECK: l_OUTLINED_FUNCTION0: ## @OUTLINED_FUNCTION0 +; CHECK: .cfi_startproc +; CHECK: ## BB#0: +; CHECK: movl $1, -12(%rbp) +; CHECK: movl $2, -8(%rbp) +; CHECK: movl $3, -4(%rbp) +; CHECK: retq \ No newline at end of file