From f27e5a09a0d815b8a4814152954ff87dadfdefc0 Mon Sep 17 00:00:00 2001 From: ed Date: Tue, 2 Jun 2009 17:58:47 +0000 Subject: Import Clang, at r72732. --- lib/Frontend/Backend.cpp | 415 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 415 insertions(+) create mode 100644 lib/Frontend/Backend.cpp (limited to 'lib/Frontend/Backend.cpp') diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp new file mode 100644 index 0000000..44aa3a8 --- /dev/null +++ b/lib/Frontend/Backend.cpp @@ -0,0 +1,415 @@ +//===--- Backend.cpp - Interface to LLVM backend technologies -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/ASTConsumers.h" +#include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Frontend/CompileOptions.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/DeclGroup.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/Module.h" +#include "llvm/ModuleProvider.h" +#include "llvm/PassManager.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Assembly/PrintModulePass.h" +#include "llvm/Analysis/CallGraph.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/CodeGen/RegAllocRegistry.h" +#include "llvm/CodeGen/SchedulerRegistry.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Timer.h" +#include "llvm/System/Path.h" +#include "llvm/System/Program.h" +#include "llvm/Target/SubtargetFeature.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetMachineRegistry.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/IPO.h" +using namespace clang; +using namespace llvm; + +namespace { + class VISIBILITY_HIDDEN BackendConsumer : public ASTConsumer { + BackendAction Action; + CompileOptions CompileOpts; + llvm::raw_ostream *AsmOutStream; + ASTContext *Context; + + Timer LLVMIRGeneration; + Timer CodeGenerationTime; + + llvm::OwningPtr Gen; + + llvm::Module *TheModule; + llvm::TargetData *TheTargetData; + + mutable llvm::ModuleProvider *ModuleProvider; + mutable FunctionPassManager *CodeGenPasses; + mutable PassManager *PerModulePasses; + mutable FunctionPassManager *PerFunctionPasses; + + FunctionPassManager *getCodeGenPasses() const; + PassManager *getPerModulePasses() const; + FunctionPassManager *getPerFunctionPasses() const; + + void CreatePasses(); + + /// AddEmitPasses - Add passes necessary to emit assembly or LLVM + /// IR. + /// + /// \return True on success. On failure \arg Error will be set to + /// a user readable error message. + bool AddEmitPasses(std::string &Error); + + void EmitAssembly(); + + public: + BackendConsumer(BackendAction action, Diagnostic &Diags, + const LangOptions &langopts, const CompileOptions &compopts, + const std::string &infile, llvm::raw_ostream* OS) : + Action(action), + CompileOpts(compopts), + AsmOutStream(OS), + LLVMIRGeneration("LLVM IR Generation Time"), + CodeGenerationTime("Code Generation Time"), + Gen(CreateLLVMCodeGen(Diags, infile, compopts)), + TheModule(0), TheTargetData(0), ModuleProvider(0), + CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) { + + // Enable -time-passes if -ftime-report is enabled. + llvm::TimePassesIsEnabled = CompileOpts.TimePasses; + } + + ~BackendConsumer() { + delete TheTargetData; + delete ModuleProvider; + delete CodeGenPasses; + delete PerModulePasses; + delete PerFunctionPasses; + } + + virtual void Initialize(ASTContext &Ctx) { + Context = &Ctx; + + if (CompileOpts.TimePasses) + LLVMIRGeneration.startTimer(); + + Gen->Initialize(Ctx); + + TheModule = Gen->GetModule(); + ModuleProvider = new ExistingModuleProvider(TheModule); + TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription()); + + if (CompileOpts.TimePasses) + LLVMIRGeneration.stopTimer(); + } + + virtual void HandleTopLevelDecl(DeclGroupRef D) { + PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(), + Context->getSourceManager(), + "LLVM IR generation of declaration"); + + if (CompileOpts.TimePasses) + LLVMIRGeneration.startTimer(); + + Gen->HandleTopLevelDecl(D); + + if (CompileOpts.TimePasses) + LLVMIRGeneration.stopTimer(); + } + + virtual void HandleTranslationUnit(ASTContext &C) { + { + PrettyStackTraceString CrashInfo("Per-file LLVM IR generation"); + if (CompileOpts.TimePasses) + LLVMIRGeneration.startTimer(); + + Gen->HandleTranslationUnit(C); + + if (CompileOpts.TimePasses) + LLVMIRGeneration.stopTimer(); + } + + // EmitAssembly times and registers crash info itself. + EmitAssembly(); + + // Force a flush here in case we never get released. + if (AsmOutStream) + AsmOutStream->flush(); + } + + virtual void HandleTagDeclDefinition(TagDecl *D) { + PrettyStackTraceDecl CrashInfo(D, SourceLocation(), + Context->getSourceManager(), + "LLVM IR generation of declaration"); + Gen->HandleTagDeclDefinition(D); + } + + virtual void CompleteTentativeDefinition(VarDecl *D) { + Gen->CompleteTentativeDefinition(D); + } + }; +} + +FunctionPassManager *BackendConsumer::getCodeGenPasses() const { + if (!CodeGenPasses) { + CodeGenPasses = new FunctionPassManager(ModuleProvider); + CodeGenPasses->add(new TargetData(*TheTargetData)); + } + + return CodeGenPasses; +} + +PassManager *BackendConsumer::getPerModulePasses() const { + if (!PerModulePasses) { + PerModulePasses = new PassManager(); + PerModulePasses->add(new TargetData(*TheTargetData)); + } + + return PerModulePasses; +} + +FunctionPassManager *BackendConsumer::getPerFunctionPasses() const { + if (!PerFunctionPasses) { + PerFunctionPasses = new FunctionPassManager(ModuleProvider); + PerFunctionPasses->add(new TargetData(*TheTargetData)); + } + + return PerFunctionPasses; +} + +bool BackendConsumer::AddEmitPasses(std::string &Error) { + if (Action == Backend_EmitNothing) + return true; + + if (Action == Backend_EmitBC) { + getPerModulePasses()->add(createBitcodeWriterPass(*AsmOutStream)); + } else if (Action == Backend_EmitLL) { + getPerModulePasses()->add(createPrintModulePass(AsmOutStream)); + } else { + bool Fast = CompileOpts.OptimizationLevel == 0; + + // Create the TargetMachine for generating code. + const TargetMachineRegistry::entry *TME = + TargetMachineRegistry::getClosestStaticTargetForModule(*TheModule, Error); + if (!TME) { + Error = std::string("Unable to get target machine: ") + Error; + return false; + } + + std::string FeaturesStr; + if (CompileOpts.CPU.size() || CompileOpts.Features.size()) { + SubtargetFeatures Features; + Features.setCPU(CompileOpts.CPU); + for (std::vector::iterator + it = CompileOpts.Features.begin(), + ie = CompileOpts.Features.end(); it != ie; ++it) + Features.AddFeature(*it); + FeaturesStr = Features.getString(); + } + TargetMachine *TM = TME->CtorFn(*TheModule, FeaturesStr); + + // Set register scheduler & allocation policy. + RegisterScheduler::setDefault(createDefaultScheduler); + RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator : + createLinearScanRegisterAllocator); + + // From llvm-gcc: + // If there are passes we have to run on the entire module, we do codegen + // as a separate "pass" after that happens. + // FIXME: This is disabled right now until bugs can be worked out. Reenable + // this for fast -O0 compiles! + FunctionPassManager *PM = getCodeGenPasses(); + CodeGenOpt::Level OptLevel = CodeGenOpt::Default; + + switch (CompileOpts.OptimizationLevel) { + default: break; + case 0: OptLevel = CodeGenOpt::None; break; + case 3: OptLevel = CodeGenOpt::Aggressive; break; + } + + // Normal mode, emit a .s file by running the code generator. + // Note, this also adds codegenerator level optimization passes. + switch (TM->addPassesToEmitFile(*PM, *AsmOutStream, + TargetMachine::AssemblyFile, OptLevel)) { + default: + case FileModel::Error: + Error = "Unable to interface with target machine!\n"; + return false; + case FileModel::AsmFile: + break; + } + + if (TM->addPassesToEmitFileFinish(*CodeGenPasses, (MachineCodeEmitter *)0, + OptLevel)) { + Error = "Unable to interface with target machine!\n"; + return false; + } + } + + return true; +} + +void BackendConsumer::CreatePasses() { + // In -O0 if checking is disabled, we don't even have per-function passes. + if (CompileOpts.VerifyModule) + getPerFunctionPasses()->add(createVerifierPass()); + + if (CompileOpts.OptimizationLevel > 0) { + FunctionPassManager *PM = getPerFunctionPasses(); + PM->add(createCFGSimplificationPass()); + if (CompileOpts.OptimizationLevel == 1) + PM->add(createPromoteMemoryToRegisterPass()); + else + PM->add(createScalarReplAggregatesPass()); + PM->add(createInstructionCombiningPass()); + } + + // For now we always create per module passes. + PassManager *PM = getPerModulePasses(); + if (CompileOpts.OptimizationLevel > 0) { + if (CompileOpts.UnitAtATime) + PM->add(createRaiseAllocationsPass()); // call %malloc -> malloc inst + PM->add(createCFGSimplificationPass()); // Clean up disgusting code + PM->add(createPromoteMemoryToRegisterPass()); // Kill useless allocas + if (CompileOpts.UnitAtATime) { + PM->add(createGlobalOptimizerPass()); // Optimize out global vars + PM->add(createGlobalDCEPass()); // Remove unused fns and globs + PM->add(createIPConstantPropagationPass()); // IP Constant Propagation + PM->add(createDeadArgEliminationPass()); // Dead argument elimination + } + PM->add(createInstructionCombiningPass()); // Clean up after IPCP & DAE + PM->add(createCFGSimplificationPass()); // Clean up after IPCP & DAE + if (CompileOpts.UnitAtATime) { + PM->add(createPruneEHPass()); // Remove dead EH info + PM->add(createFunctionAttrsPass()); // Set readonly/readnone attrs + } + if (CompileOpts.InlineFunctions) + PM->add(createFunctionInliningPass()); // Inline small functions + else + PM->add(createAlwaysInlinerPass()); // Respect always_inline + if (CompileOpts.OptimizationLevel > 2) + PM->add(createArgumentPromotionPass()); // Scalarize uninlined fn args + if (CompileOpts.SimplifyLibCalls) + PM->add(createSimplifyLibCallsPass()); // Library Call Optimizations + PM->add(createInstructionCombiningPass()); // Cleanup for scalarrepl. + PM->add(createJumpThreadingPass()); // Thread jumps. + PM->add(createCFGSimplificationPass()); // Merge & remove BBs + PM->add(createScalarReplAggregatesPass()); // Break up aggregate allocas + PM->add(createInstructionCombiningPass()); // Combine silly seq's + PM->add(createCondPropagationPass()); // Propagate conditionals + PM->add(createTailCallEliminationPass()); // Eliminate tail calls + PM->add(createCFGSimplificationPass()); // Merge & remove BBs + PM->add(createReassociatePass()); // Reassociate expressions + PM->add(createLoopRotatePass()); // Rotate Loop + PM->add(createLICMPass()); // Hoist loop invariants + PM->add(createLoopUnswitchPass(CompileOpts.OptimizeSize ? true : false)); +// PM->add(createLoopIndexSplitPass()); // Split loop index + PM->add(createInstructionCombiningPass()); + PM->add(createIndVarSimplifyPass()); // Canonicalize indvars + PM->add(createLoopDeletionPass()); // Delete dead loops + if (CompileOpts.UnrollLoops) + PM->add(createLoopUnrollPass()); // Unroll small loops + PM->add(createInstructionCombiningPass()); // Clean up after the unroller + PM->add(createGVNPass()); // Remove redundancies + PM->add(createMemCpyOptPass()); // Remove memcpy / form memset + PM->add(createSCCPPass()); // Constant prop with SCCP + + // Run instcombine after redundancy elimination to exploit opportunities + // opened up by them. + PM->add(createInstructionCombiningPass()); + PM->add(createCondPropagationPass()); // Propagate conditionals + PM->add(createDeadStoreEliminationPass()); // Delete dead stores + PM->add(createAggressiveDCEPass()); // Delete dead instructions + PM->add(createCFGSimplificationPass()); // Merge & remove BBs + + if (CompileOpts.UnitAtATime) { + PM->add(createStripDeadPrototypesPass()); // Get rid of dead prototypes + PM->add(createDeadTypeEliminationPass()); // Eliminate dead types + } + + if (CompileOpts.OptimizationLevel > 1 && CompileOpts.UnitAtATime) + PM->add(createConstantMergePass()); // Merge dup global constants + } else { + PM->add(createAlwaysInlinerPass()); + } +} + +/// EmitAssembly - Handle interaction with LLVM backend to generate +/// actual machine code. +void BackendConsumer::EmitAssembly() { + // Silently ignore if we weren't initialized for some reason. + if (!TheModule || !TheTargetData) + return; + + + TimeRegion Region(CompileOpts.TimePasses ? &CodeGenerationTime : 0); + + // Make sure IR generation is happy with the module. This is + // released by the module provider. + Module *M = Gen->ReleaseModule(); + if (!M) { + // The module has been released by IR gen on failures, do not + // double free. + ModuleProvider->releaseModule(); + TheModule = 0; + return; + } + + assert(TheModule == M && "Unexpected module change during IR generation"); + + CreatePasses(); + + std::string Error; + if (!AddEmitPasses(Error)) { + // FIXME: Don't fail this way. + llvm::cerr << "ERROR: " << Error << "\n"; + ::exit(1); + } + + // Run passes. For now we do all passes at once, but eventually we + // would like to have the option of streaming code generation. + + if (PerFunctionPasses) { + PrettyStackTraceString CrashInfo("Per-function optimization"); + + PerFunctionPasses->doInitialization(); + for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) + if (!I->isDeclaration()) + PerFunctionPasses->run(*I); + PerFunctionPasses->doFinalization(); + } + + if (PerModulePasses) { + PrettyStackTraceString CrashInfo("Per-module optimization passes"); + PerModulePasses->run(*M); + } + + if (CodeGenPasses) { + PrettyStackTraceString CrashInfo("Code generation"); + CodeGenPasses->doInitialization(); + for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) + if (!I->isDeclaration()) + CodeGenPasses->run(*I); + CodeGenPasses->doFinalization(); + } +} + +ASTConsumer *clang::CreateBackendConsumer(BackendAction Action, + Diagnostic &Diags, + const LangOptions &LangOpts, + const CompileOptions &CompileOpts, + const std::string& InFile, + llvm::raw_ostream* OS) { + return new BackendConsumer(Action, Diags, LangOpts, CompileOpts, InFile, OS); +} -- cgit v1.1