| //===- LLVMTargetMachine.cpp ----------------------------------------------===// |
| // |
| // The MCLinker Project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "mcld/CodeGen/SectLinker.h" |
| #include "mcld/CodeGen/SectLinkerOption.h" |
| #include "mcld/MC/MCBitcodeInterceptor.h" |
| #include "mcld/MC/MCLDFile.h" |
| #include "mcld/Support/RealPath.h" |
| #include "mcld/Support/TargetRegistry.h" |
| #include "mcld/Target/TargetMachine.h" |
| #include "mcld/Target/TargetLDBackend.h" |
| |
| #include <llvm/ADT/OwningPtr.h> |
| #include <llvm/Analysis/Passes.h> |
| #include <llvm/Analysis/Verifier.h> |
| #include <llvm/Assembly/PrintModulePass.h> |
| #include <llvm/CodeGen/AsmPrinter.h> |
| #include <llvm/CodeGen/MachineFunctionAnalysis.h> |
| #include <llvm/CodeGen/MachineModuleInfo.h> |
| #include <llvm/CodeGen/GCStrategy.h> |
| #include <llvm/CodeGen/Passes.h> |
| #include <llvm/MC/MCAsmInfo.h> |
| #include <llvm/MC/MCStreamer.h> |
| #include <llvm/MC/MCInstrInfo.h> |
| #include <llvm/MC/MCSubtargetInfo.h> |
| #include <llvm/MC/MCObjectStreamer.h> |
| #include <llvm/MC/MCAssembler.h> |
| #include <llvm/MC/MCObjectWriter.h> |
| #include <llvm/MC/MCContext.h> |
| #include <llvm/PassManager.h> |
| #include <llvm/Support/CommandLine.h> |
| #include <llvm/Support/Debug.h> |
| #include <llvm/Support/TargetRegistry.h> |
| #include <llvm/Support/FormattedStream.h> |
| #include <llvm/Support/ToolOutputFile.h> |
| #include <llvm/Target/TargetData.h> |
| #include <llvm/Target/TargetInstrInfo.h> |
| #include <llvm/Target/TargetLowering.h> |
| #include <llvm/Target/TargetOptions.h> |
| #include <llvm/Target/TargetSubtargetInfo.h> |
| #include <llvm/Target/TargetLoweringObjectFile.h> |
| #include <llvm/Target/TargetRegisterInfo.h> |
| #include <llvm/Transforms/Scalar.h> |
| |
| #include <string> |
| |
| using namespace mcld; |
| using namespace llvm; |
| |
| //===----------------------------------------------------------------------===// |
| /// Arguments |
| // Enable or disable FastISel. Both options are needed, because |
| // FastISel is enabled by default with -fast, and we wish to be |
| // able to enable or disable fast-isel independently from -O0. |
| |
| static cl::opt<cl::boolOrDefault> |
| ArgEnableFastISelOption("lfast-isel", cl::Hidden, |
| cl::desc("Enable the \"fast\" instruction selector")); |
| |
| static cl::opt<bool> |
| ArgShowMCEncoding("lshow-mc-encoding", |
| cl::Hidden, |
| cl::desc("Show encoding in .s output")); |
| |
| static cl::opt<bool> |
| ArgShowMCInst("lshow-mc-inst", |
| cl::Hidden, |
| cl::desc("Show instruction structure in .s output")); |
| |
| static cl::opt<cl::boolOrDefault> |
| ArgAsmVerbose("fverbose-asm", |
| cl::desc("Put extra commentary information in the \ |
| generated assembly code to make it more readable."), |
| cl::init(cl::BOU_UNSET)); |
| |
| static bool getVerboseAsm() { |
| switch (ArgAsmVerbose) { |
| default: |
| case cl::BOU_UNSET: return TargetMachine::getAsmVerbosityDefault(); |
| case cl::BOU_TRUE: return true; |
| case cl::BOU_FALSE: return false; |
| } |
| } |
| |
| |
| //===---------------------------------------------------------------------===// |
| /// LLVMTargetMachine |
| mcld::LLVMTargetMachine::LLVMTargetMachine(llvm::TargetMachine &pTM, |
| const mcld::Target& pTarget, |
| const std::string& pTriple ) |
| : m_TM(pTM), m_pTarget(&pTarget), m_Triple(pTriple) { |
| } |
| |
| mcld::LLVMTargetMachine::~LLVMTargetMachine() { |
| m_pTarget = 0; |
| } |
| |
| const mcld::Target& mcld::LLVMTargetMachine::getTarget() const |
| { |
| return *m_pTarget; |
| } |
| |
| /// Turn exception handling constructs into something the code generators can |
| /// handle. |
| static void addPassesToHandleExceptions(llvm::TargetMachine *TM, |
| PassManagerBase &PM) { |
| switch (TM->getMCAsmInfo()->getExceptionHandlingType()) { |
| case llvm::ExceptionHandling::SjLj: |
| // SjLj piggy-backs on dwarf for this bit. The cleanups done apply to both |
| // Dwarf EH prepare needs to be run after SjLj prepare. Otherwise, |
| // catch info can get misplaced when a selector ends up more than one block |
| // removed from the parent invoke(s). This could happen when a landing |
| // pad is shared by multiple invokes and is also a target of a normal |
| // edge from elsewhere. |
| PM.add(createSjLjEHPreparePass(TM->getTargetLowering())); |
| // FALLTHROUGH |
| case llvm::ExceptionHandling::DwarfCFI: |
| case llvm::ExceptionHandling::ARM: |
| case llvm::ExceptionHandling::Win64: |
| PM.add(createDwarfEHPass(TM)); |
| break; |
| case llvm::ExceptionHandling::None: |
| PM.add(createLowerInvokePass(TM->getTargetLowering())); |
| |
| // The lower invoke pass may create unreachable code. Remove it. |
| PM.add(createUnreachableBlockEliminationPass()); |
| break; |
| } |
| } |
| |
| |
| static llvm::MCContext *addPassesToGenerateCode(llvm::LLVMTargetMachine *TM, |
| PassManagerBase &PM, |
| bool DisableVerify) |
| { |
| // Targets may override createPassConfig to provide a target-specific sublass. |
| TargetPassConfig *PassConfig = TM->createPassConfig(PM); |
| |
| // Set PassConfig options provided by TargetMachine. |
| PassConfig->setDisableVerify(DisableVerify); |
| |
| PM.add(PassConfig); |
| |
| PassConfig->addIRPasses(); |
| |
| addPassesToHandleExceptions(TM, PM); |
| |
| PassConfig->addISelPrepare(); |
| |
| // Install a MachineModuleInfo class, which is an immutable pass that holds |
| // all the per-module stuff we're generating, including MCContext. |
| MachineModuleInfo *MMI = |
| new MachineModuleInfo(*TM->getMCAsmInfo(), *TM->getRegisterInfo(), |
| &TM->getTargetLowering()->getObjFileLowering()); |
| PM.add(MMI); |
| MCContext *Context = &MMI->getContext(); // Return the MCContext by-ref. |
| |
| // Set up a MachineFunction for the rest of CodeGen to work on. |
| PM.add(new MachineFunctionAnalysis(*TM)); |
| |
| // Enable FastISel with -fast, but allow that to be overridden. |
| if (ArgEnableFastISelOption == cl::BOU_TRUE || |
| (TM->getOptLevel() == CodeGenOpt::None && |
| ArgEnableFastISelOption != cl::BOU_FALSE)) |
| TM->setFastISel(true); |
| |
| // Ask the target for an isel. |
| if (PassConfig->addInstSelector()) |
| return NULL; |
| |
| PassConfig->addMachinePasses(); |
| |
| PassConfig->setInitialized(); |
| |
| return Context; |
| |
| } |
| |
| bool mcld::LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &pPM, |
| formatted_raw_ostream &Out, |
| const std::string& pOutputFilename, |
| mcld::CodeGenFileType pFileType, |
| CodeGenOpt::Level pOptLvl, |
| SectLinkerOption *pLinkerOpt, |
| bool pDisableVerify) |
| { |
| |
| llvm::MCContext* Context = |
| addPassesToGenerateCode(static_cast<llvm::LLVMTargetMachine*>(&m_TM), |
| pPM, pDisableVerify); |
| if (!Context) |
| return true; |
| |
| switch(pFileType) { |
| default: |
| case mcld::CGFT_NULLFile: |
| assert(0 && "fatal: file type is not set!"); |
| break; |
| case CGFT_ASMFile: { |
| assert(Context != 0 && "Failed to get MCContext"); |
| |
| if (getTM().hasMCSaveTempLabels()) |
| Context->setAllowTemporaryLabels(false); |
| |
| if (addCompilerPasses(pPM, |
| Out, |
| pOutputFilename, |
| Context)) |
| return true; |
| |
| pPM.add(createGCInfoDeleter()); // not in addPassesToMC |
| break; |
| } |
| case CGFT_OBJFile: { |
| assert(Context != 0 && "Failed to get MCContext"); |
| |
| if (getTM().hasMCSaveTempLabels()) |
| Context->setAllowTemporaryLabels(false); |
| if (addAssemblerPasses(pPM, |
| Out, |
| pOutputFilename, |
| Context)) |
| return true; |
| |
| pPM.add(createGCInfoDeleter()); // not in addPassesToMC |
| break; |
| } |
| case CGFT_ARCFile: { |
| assert(0 && "Output to archive file has not been supported yet!"); |
| break; |
| } |
| case CGFT_EXEFile: { |
| if (pLinkerOpt == NULL) |
| return true; |
| |
| if (addLinkerPasses(pPM, |
| pLinkerOpt, |
| pOutputFilename, |
| MCLDFile::Exec, |
| Context)) |
| return true; |
| break; |
| } |
| case CGFT_DSOFile: { |
| if (pLinkerOpt == NULL) |
| return true; |
| |
| if (addLinkerPasses(pPM, |
| pLinkerOpt, |
| pOutputFilename, |
| MCLDFile::DynObj, |
| Context)) |
| return true; |
| break; |
| } |
| } // switch |
| return false; |
| } |
| |
| bool mcld::LLVMTargetMachine::addCompilerPasses(PassManagerBase &pPM, |
| formatted_raw_ostream &Out, |
| const std::string& pOutputFilename, |
| llvm::MCContext *&Context) |
| { |
| const MCAsmInfo &MAI = *getTM().getMCAsmInfo(); |
| const MCSubtargetInfo &STI = getTM().getSubtarget<MCSubtargetInfo>(); |
| |
| MCInstPrinter *InstPrinter = |
| getTarget().get()->createMCInstPrinter(MAI.getAssemblerDialect(), MAI, |
| *(getTM().getInstrInfo()), |
| Context->getRegisterInfo(), STI); |
| |
| MCCodeEmitter* MCE = 0; |
| MCAsmBackend *MAB = 0; |
| if (ArgShowMCEncoding) { |
| MCE = getTarget().get()->createMCCodeEmitter(*(getTM().getInstrInfo()), STI, *Context); |
| MAB = getTarget().get()->createMCAsmBackend(m_Triple); |
| } |
| |
| |
| // now, we have MCCodeEmitter and MCAsmBackend, we can create AsmStreamer. |
| OwningPtr<MCStreamer> AsmStreamer( |
| getTarget().get()->createAsmStreamer(*Context, Out, |
| getVerboseAsm(), |
| getTM().hasMCUseLoc(), |
| getTM().hasMCUseCFI(), |
| getTM().hasMCUseDwarfDirectory(), |
| InstPrinter, |
| MCE, MAB, |
| ArgShowMCInst)); |
| |
| llvm::MachineFunctionPass* funcPass = |
| getTarget().get()->createAsmPrinter(getTM(), *AsmStreamer.get()); |
| |
| if (funcPass == 0) |
| return true; |
| // If successful, createAsmPrinter took ownership of AsmStreamer |
| AsmStreamer.take(); |
| pPM.add(funcPass); |
| return false; |
| } |
| |
| bool mcld::LLVMTargetMachine::addAssemblerPasses(PassManagerBase &pPM, |
| formatted_raw_ostream &Out, |
| const std::string& pOutputFilename, |
| llvm::MCContext *&Context) |
| { |
| // MCCodeEmitter |
| const MCSubtargetInfo &STI = getTM().getSubtarget<MCSubtargetInfo>(); |
| MCCodeEmitter* MCE = getTarget().get()->createMCCodeEmitter(*getTM().getInstrInfo(), STI, *Context); |
| |
| // MCAsmBackend |
| MCAsmBackend* MAB = getTarget().get()->createMCAsmBackend(m_Triple); |
| if (MCE == 0 || MAB == 0) |
| return true; |
| |
| // now, we have MCCodeEmitter and MCAsmBackend, we can create AsmStreamer. |
| OwningPtr<MCStreamer> AsmStreamer(getTarget().get()->createMCObjectStreamer( |
| m_Triple, |
| *Context, |
| *MAB, |
| Out, |
| MCE, |
| getTM().hasMCRelaxAll(), |
| getTM().hasMCNoExecStack())); |
| AsmStreamer.get()->InitSections(); |
| MachineFunctionPass *funcPass = getTarget().get()->createAsmPrinter(getTM(), |
| *AsmStreamer.get()); |
| if (funcPass == 0) |
| return true; |
| // If successful, createAsmPrinter took ownership of AsmStreamer |
| AsmStreamer.take(); |
| pPM.add(funcPass); |
| return false; |
| } |
| |
| bool mcld::LLVMTargetMachine::addLinkerPasses(PassManagerBase &pPM, |
| SectLinkerOption *pLinkerOpt, |
| const std::string &pOutputFilename, |
| MCLDFile::Type pOutputLinkType, |
| llvm::MCContext *&Context) |
| { |
| // FIXME: when MCLinker can directly turn bitcode into shared object, turn on this |
| // block of code. |
| #if 0 |
| // Initialize MCAsmStreamer first, than chain its output into SectLinker. |
| // MCCodeEmitter |
| const MCSubtargetInfo &STI = getTM().getSubtarget<MCSubtargetInfo>(); |
| MCCodeEmitter* MCE = getTarget().get()->createMCCodeEmitter(*getTM().getInstrInfo(), |
| STI, |
| *Context); |
| // MCAsmBackend |
| MCAsmBackend *MAB = getTarget().get()->createMCAsmBackend(m_Triple); |
| if (MCE == 0 || MAB == 0) |
| return true; |
| |
| // now, we have MCCodeEmitter and MCAsmBackend, we can create AsmStreamer. |
| MCStreamer* AsmStreamer = |
| getTarget().get()->createMCObjectStreamer(m_Triple, |
| *Context, |
| *MAB, |
| llvm::nulls(), |
| MCE, |
| getTM().hasMCRelaxAll(), |
| getTM().hasMCNoExecStack()); |
| if (0 == AsmStreamer) |
| return true; |
| |
| AsmStreamer->InitSections(); |
| AsmPrinter* printer = getTarget().get()->createAsmPrinter(getTM(), *AsmStreamer); |
| if (0 == printer) |
| return true; |
| pPM.add(printer); |
| #endif |
| TargetLDBackend* ldBackend = getTarget().createLDBackend(*getTarget().get(), m_Triple); |
| if (0 == ldBackend) |
| return true; |
| |
| // FIXME: when MCLinker can directly turn bitcode into shared object, turn on this |
| // block of code. |
| #if 0 |
| MCBitcodeInterceptor* objReader = new MCBitcodeInterceptor( |
| static_cast<MCObjectStreamer&>(*AsmStreamer), |
| *ldBackend, |
| getLDInfo()); |
| #endif |
| // set up output's SOName |
| if (pOutputLinkType == MCLDFile::DynObj && |
| pLinkerOpt->info().output().name().empty()) { |
| // if the output is a shared object, and the option -soname was not |
| // enable, set soname as the output file name. |
| pLinkerOpt->info().output().setSOName(pOutputFilename); |
| } |
| |
| pLinkerOpt->info().output().setPath(sys::fs::RealPath(pOutputFilename)); |
| pLinkerOpt->info().output().setType(pOutputLinkType); |
| |
| MachineFunctionPass* funcPass = getTarget().createSectLinker(m_Triple, |
| *pLinkerOpt, |
| *ldBackend); |
| if (0 == funcPass) |
| return true; |
| |
| pPM.add(funcPass); |
| return false; |
| } |