diff options
Diffstat (limited to 'lib/CodeGen/LLVMTargetMachine.cpp')
-rw-r--r-- | lib/CodeGen/LLVMTargetMachine.cpp | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/lib/CodeGen/LLVMTargetMachine.cpp b/lib/CodeGen/LLVMTargetMachine.cpp new file mode 100644 index 000000000000..b3c60e63932f --- /dev/null +++ b/lib/CodeGen/LLVMTargetMachine.cpp @@ -0,0 +1,289 @@ +//===-- LLVMTargetMachine.cpp - Implement the LLVMTargetMachine class -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the LLVMTargetMachine class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Target/TargetMachine.h" +#include "llvm/PassManager.h" +#include "llvm/Pass.h" +#include "llvm/Assembly/PrintModulePass.h" +#include "llvm/Analysis/LoopPass.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/GCStrategy.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +namespace llvm { + bool EnableFastISel; +} + +static cl::opt<bool> PrintLSR("print-lsr-output", cl::Hidden, + cl::desc("Print LLVM IR produced by the loop-reduce pass")); +static cl::opt<bool> PrintISelInput("print-isel-input", cl::Hidden, + cl::desc("Print LLVM IR input to isel pass")); +static cl::opt<bool> PrintEmittedAsm("print-emitted-asm", cl::Hidden, + cl::desc("Dump emitter generated instructions as assembly")); +static cl::opt<bool> PrintGCInfo("print-gc", cl::Hidden, + cl::desc("Dump garbage collector data")); +static cl::opt<bool> VerifyMachineCode("verify-machineinstrs", cl::Hidden, + cl::desc("Verify generated machine code"), + cl::init(getenv("LLVM_VERIFY_MACHINEINSTRS")!=NULL)); + +// When this works it will be on by default. +static cl::opt<bool> +DisablePostRAScheduler("disable-post-RA-scheduler", + cl::desc("Disable scheduling after register allocation"), + cl::init(true)); + +// 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 -fast. +static cl::opt<cl::boolOrDefault> +EnableFastISelOption("fast-isel", cl::Hidden, + cl::desc("Enable the experimental \"fast\" instruction selector")); + +FileModel::Model +LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM, + raw_ostream &Out, + CodeGenFileType FileType, + CodeGenOpt::Level OptLevel) { + // Add common CodeGen passes. + if (addCommonCodeGenPasses(PM, OptLevel)) + return FileModel::Error; + + // Fold redundant debug labels. + PM.add(createDebugLabelFoldingPass()); + + if (PrintMachineCode) + PM.add(createMachineFunctionPrinterPass(cerr)); + + if (addPreEmitPass(PM, OptLevel) && PrintMachineCode) + PM.add(createMachineFunctionPrinterPass(cerr)); + + if (OptLevel != CodeGenOpt::None) + PM.add(createCodePlacementOptPass()); + + switch (FileType) { + default: + break; + case TargetMachine::AssemblyFile: + if (addAssemblyEmitter(PM, OptLevel, getAsmVerbosityDefault(), Out)) + return FileModel::Error; + return FileModel::AsmFile; + case TargetMachine::ObjectFile: + if (getMachOWriterInfo()) + return FileModel::MachOFile; + else if (getELFWriterInfo()) + return FileModel::ElfFile; + } + + return FileModel::Error; +} + +/// addPassesToEmitFileFinish - If the passes to emit the specified file had to +/// be split up (e.g., to add an object writer pass), this method can be used to +/// finish up adding passes to emit the file, if necessary. +bool LLVMTargetMachine::addPassesToEmitFileFinish(PassManagerBase &PM, + MachineCodeEmitter *MCE, + CodeGenOpt::Level OptLevel) { + if (MCE) + addSimpleCodeEmitter(PM, OptLevel, PrintEmittedAsm, *MCE); + + PM.add(createGCInfoDeleter()); + + // Delete machine code for this function + PM.add(createMachineCodeDeleter()); + + return false; // success! +} + +/// addPassesToEmitFileFinish - If the passes to emit the specified file had to +/// be split up (e.g., to add an object writer pass), this method can be used to +/// finish up adding passes to emit the file, if necessary. +bool LLVMTargetMachine::addPassesToEmitFileFinish(PassManagerBase &PM, + JITCodeEmitter *JCE, + CodeGenOpt::Level OptLevel) { + if (JCE) + addSimpleCodeEmitter(PM, OptLevel, PrintEmittedAsm, *JCE); + + PM.add(createGCInfoDeleter()); + + // Delete machine code for this function + PM.add(createMachineCodeDeleter()); + + return false; // success! +} + +/// addPassesToEmitMachineCode - Add passes to the specified pass manager to +/// get machine code emitted. This uses a MachineCodeEmitter object to handle +/// actually outputting the machine code and resolving things like the address +/// of functions. This method should returns true if machine code emission is +/// not supported. +/// +bool LLVMTargetMachine::addPassesToEmitMachineCode(PassManagerBase &PM, + MachineCodeEmitter &MCE, + CodeGenOpt::Level OptLevel) { + // Add common CodeGen passes. + if (addCommonCodeGenPasses(PM, OptLevel)) + return true; + + if (addPreEmitPass(PM, OptLevel) && PrintMachineCode) + PM.add(createMachineFunctionPrinterPass(cerr)); + + addCodeEmitter(PM, OptLevel, PrintEmittedAsm, MCE); + + PM.add(createGCInfoDeleter()); + + // Delete machine code for this function + PM.add(createMachineCodeDeleter()); + + return false; // success! +} + +/// addPassesToEmitMachineCode - Add passes to the specified pass manager to +/// get machine code emitted. This uses a MachineCodeEmitter object to handle +/// actually outputting the machine code and resolving things like the address +/// of functions. This method should returns true if machine code emission is +/// not supported. +/// +bool LLVMTargetMachine::addPassesToEmitMachineCode(PassManagerBase &PM, + JITCodeEmitter &JCE, + CodeGenOpt::Level OptLevel) { + // Add common CodeGen passes. + if (addCommonCodeGenPasses(PM, OptLevel)) + return true; + + if (addPreEmitPass(PM, OptLevel) && PrintMachineCode) + PM.add(createMachineFunctionPrinterPass(cerr)); + + addCodeEmitter(PM, OptLevel, PrintEmittedAsm, JCE); + + PM.add(createGCInfoDeleter()); + + // Delete machine code for this function + PM.add(createMachineCodeDeleter()); + + return false; // success! +} + +static void printAndVerify(PassManagerBase &PM, + bool allowDoubleDefs = false) { + if (PrintMachineCode) + PM.add(createMachineFunctionPrinterPass(cerr)); + + if (VerifyMachineCode) + PM.add(createMachineVerifierPass(allowDoubleDefs)); +} + +/// addCommonCodeGenPasses - Add standard LLVM codegen passes used for both +/// emitting to assembly files or machine code output. +/// +bool LLVMTargetMachine::addCommonCodeGenPasses(PassManagerBase &PM, + CodeGenOpt::Level OptLevel) { + // Standard LLVM-Level Passes. + + // Run loop strength reduction before anything else. + if (OptLevel != CodeGenOpt::None) { + PM.add(createLoopStrengthReducePass(getTargetLowering())); + if (PrintLSR) + PM.add(createPrintFunctionPass("\n\n*** Code after LSR ***\n", &errs())); + } + + // Turn exception handling constructs into something the code generators can + // handle. + if (!getTargetAsmInfo()->doesSupportExceptionHandling()) + PM.add(createLowerInvokePass(getTargetLowering())); + else + PM.add(createDwarfEHPass(getTargetLowering(), OptLevel==CodeGenOpt::None)); + + PM.add(createGCLoweringPass()); + + // Make sure that no unreachable blocks are instruction selected. + PM.add(createUnreachableBlockEliminationPass()); + + if (OptLevel != CodeGenOpt::None) + PM.add(createCodeGenPreparePass(getTargetLowering())); + + PM.add(createStackProtectorPass(getTargetLowering())); + + if (PrintISelInput) + PM.add(createPrintFunctionPass("\n\n" + "*** Final LLVM Code input to ISel ***\n", + &errs())); + + // Standard Lower-Level Passes. + + // Enable FastISel with -fast, but allow that to be overridden. + if (EnableFastISelOption == cl::BOU_TRUE || + (OptLevel == CodeGenOpt::None && EnableFastISelOption != cl::BOU_FALSE)) + EnableFastISel = true; + + // Ask the target for an isel. + if (addInstSelector(PM, OptLevel)) + return true; + + // Print the instruction selected machine code... + printAndVerify(PM, /* allowDoubleDefs= */ true); + + if (OptLevel != CodeGenOpt::None) { + PM.add(createMachineLICMPass()); + PM.add(createMachineSinkingPass()); + printAndVerify(PM, /* allowDoubleDefs= */ true); + } + + // Run pre-ra passes. + if (addPreRegAlloc(PM, OptLevel)) + printAndVerify(PM); + + // Perform register allocation. + PM.add(createRegisterAllocator()); + + // Perform stack slot coloring. + if (OptLevel != CodeGenOpt::None) + PM.add(createStackSlotColoringPass(OptLevel >= CodeGenOpt::Aggressive)); + + printAndVerify(PM); // Print the register-allocated code + + // Run post-ra passes. + if (addPostRegAlloc(PM, OptLevel)) + printAndVerify(PM); + + PM.add(createLowerSubregsPass()); + printAndVerify(PM); + + // Insert prolog/epilog code. Eliminate abstract frame index references... + PM.add(createPrologEpilogCodeInserter()); + printAndVerify(PM); + + // Second pass scheduler. + if (OptLevel != CodeGenOpt::None && !DisablePostRAScheduler) { + PM.add(createPostRAScheduler()); + printAndVerify(PM); + } + + // Branch folding must be run after regalloc and prolog/epilog insertion. + if (OptLevel != CodeGenOpt::None) { + PM.add(createBranchFoldingPass(getEnableTailMergeDefault())); + printAndVerify(PM); + } + + PM.add(createGCMachineCodeAnalysisPass()); + printAndVerify(PM); + + if (PrintGCInfo) + PM.add(createGCInfoPrinter(*cerr)); + + return false; +} |