diff options
-rw-r--r-- | Driver/ASTConsumers.cpp | 84 | ||||
-rw-r--r-- | Driver/ASTConsumers.h | 16 | ||||
-rw-r--r-- | Driver/Backend.cpp | 297 | ||||
-rw-r--r-- | Driver/Makefile | 21 | ||||
-rw-r--r-- | Driver/clang.cpp | 12 |
5 files changed, 332 insertions, 98 deletions
diff --git a/Driver/ASTConsumers.cpp b/Driver/ASTConsumers.cpp index 24335cfae0..dbed6a2c30 100644 --- a/Driver/ASTConsumers.cpp +++ b/Driver/ASTConsumers.cpp @@ -21,12 +21,8 @@ #include "clang/AST/ASTConsumer.h" #include "clang/CodeGen/ModuleBuilder.h" #include "llvm/Module.h" -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/Support/Streams.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/ADT/OwningPtr.h" -#include <fstream> using namespace clang; @@ -652,83 +648,3 @@ ASTConsumer* clang::CreateASTSerializer(const std::string& InFile, FName.appendSuffix("ast"); return new SingleFileSerializer(FName, Diags); } - -class LLVMCodeGenWriter : public ASTConsumer { - llvm::OwningPtr<CodeGenerator> Gen; - const std::string &InFile; - const std::string &OutputFile; - bool EmitBitcode; -public: - - LLVMCodeGenWriter(bool EmitBC, Diagnostic &Diags, const LangOptions &Features, - const std::string& infile, const std::string& outfile, - bool GenerateDebugInfo) - : Gen(CreateLLVMCodeGen(Diags, Features, infile, GenerateDebugInfo)), - InFile(infile), OutputFile(outfile), EmitBitcode(EmitBC) {} - - virtual void Initialize(ASTContext &Context) { - Gen->Initialize(Context); - } - - virtual void InitializeTU(TranslationUnit& TU) { - Gen->InitializeTU(TU); - } - - virtual void HandleTopLevelDecl(Decl *D) { - Gen->HandleTopLevelDecl(D); - } - - virtual void HandleTranslationUnit(TranslationUnit& TU) { - Gen->HandleTranslationUnit(TU); - } - - virtual void HandleTagDeclDefinition(TagDecl *D) { - Gen->HandleTagDeclDefinition(D); - } - - virtual ~LLVMCodeGenWriter() { - llvm::OwningPtr<llvm::Module> CodeGenModule(Gen->ReleaseModule()); - - if (!CodeGenModule) - return; - - std::ostream *Out; - - if (OutputFile == "-") { - Out = llvm::cout.stream(); - } else if (!OutputFile.empty()) { - Out = new std::ofstream(OutputFile.c_str(), - std::ios_base::binary|std::ios_base::out); - } else if (InFile == "-") { - Out = llvm::cout.stream(); - } else { - llvm::sys::Path Path(InFile); - Path.eraseSuffix(); - if (!EmitBitcode) - Path.appendSuffix("ll"); - else - Path.appendSuffix("bc"); - - Out = new std::ofstream(Path.toString().c_str(), - std::ios_base::binary|std::ios_base::out); - } - - if (!EmitBitcode) - *Out << *CodeGenModule.get(); - else - llvm::WriteBitcodeToFile(CodeGenModule.get(), *Out); - - if (Out != llvm::cout.stream()) - delete Out; - } -}; - -ASTConsumer *clang::CreateLLVMCodeGenWriter(bool EmitBC, Diagnostic &Diags, - const LangOptions &Features, - const std::string& InFile, - const std::string& OutFile, - bool GenerateDebugInfo) { - - return new LLVMCodeGenWriter(EmitBC, Diags, Features, InFile, OutFile, - GenerateDebugInfo); -} diff --git a/Driver/ASTConsumers.h b/Driver/ASTConsumers.h index c1bf2300ce..9c8af64bed 100644 --- a/Driver/ASTConsumers.h +++ b/Driver/ASTConsumers.h @@ -42,11 +42,17 @@ ASTConsumer *CreateCodeRewriterTest(const std::string& InFile, Diagnostic &Diags, const LangOptions &LOpts); -ASTConsumer *CreateLLVMCodeGenWriter(bool EmitBC, Diagnostic &Diags, - const LangOptions &Features, - const std::string& InFile, - const std::string& OutFile, - bool GenerateDebugInfo); +enum BackendAction { + Backend_EmitAssembly, + Backend_EmitBC, + Backend_EmitLL +}; +ASTConsumer *CreateBackendConsumer(BackendAction Action, + Diagnostic &Diags, + const LangOptions &Features, + const std::string& InFile, + const std::string& OutFile, + bool GenerateDebugInfo); ASTConsumer* CreateHTMLPrinter(const std::string &OutFile, Diagnostic &D, Preprocessor *PP, PreprocessorFactory* PPF); diff --git a/Driver/Backend.cpp b/Driver/Backend.cpp new file mode 100644 index 0000000000..32dbbf21a4 --- /dev/null +++ b/Driver/Backend.cpp @@ -0,0 +1,297 @@ +//===--- 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 "ASTConsumers.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/TranslationUnit.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/CodeGen/ModuleBuilder.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/Bitcode/ReaderWriter.h" +#include "llvm/CodeGen/RegAllocRegistry.h" +#include "llvm/CodeGen/SchedulerRegistry.h" +#include "llvm/CodeGen/ScheduleDAG.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Streams.h" +#include "llvm/Support/Compiler.h" +#include "llvm/System/Path.h" +#include "llvm/System/Program.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetMachineRegistry.h" +#include <fstream> // FIXME: Remove + +using namespace clang; +using namespace llvm; + +namespace { + class VISIBILITY_HIDDEN BackendConsumer : public ASTConsumer { + BackendAction Action; + const std::string &InputFile; + std::string OutputFile; + llvm::OwningPtr<CodeGenerator> Gen; + + llvm::Module *TheModule; + llvm::TargetData *TheTargetData; + llvm::raw_ostream *AsmOutStream; + + 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. + /// + /// \arg Fast - Whether "fast" native compilation should be + /// used. This implies local register allocation and fast + /// instruction selection. + /// \return True on success. On failure \arg Error will be set to + /// a user readable error message. + bool AddEmitPasses(bool Fast, std::string &Error); + + void EmitAssembly(); + + public: + BackendConsumer(BackendAction action, Diagnostic &Diags, + const LangOptions &Features, + const std::string& infile, const std::string& outfile, + bool GenerateDebugInfo) : + Action(action), + InputFile(infile), + OutputFile(outfile), + Gen(CreateLLVMCodeGen(Diags, Features, InputFile, GenerateDebugInfo)), + TheModule(0), TheTargetData(0), AsmOutStream(0), + CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) {} + + ~BackendConsumer() { + // FIXME: Move out of destructor. + EmitAssembly(); + + delete AsmOutStream; + delete TheTargetData; + delete TheModule; + delete CodeGenPasses; + delete PerModulePasses; + delete PerFunctionPasses; + } + + virtual void InitializeTU(TranslationUnit& TU) { + Gen->InitializeTU(TU); + + TheModule = Gen->GetModule(); + TheTargetData = + new llvm::TargetData(TU.getContext().Target.getTargetDescription()); + } + + virtual void HandleTopLevelDecl(Decl *D) { + Gen->HandleTopLevelDecl(D); + } + + virtual void HandleTranslationUnit(TranslationUnit& TU) { + Gen->HandleTranslationUnit(TU); + } + + virtual void HandleTagDeclDefinition(TagDecl *D) { + Gen->HandleTagDeclDefinition(D); + } + }; +} + +FunctionPassManager *BackendConsumer::getCodeGenPasses() const { + if (!CodeGenPasses) { + CodeGenPasses = + new FunctionPassManager(new ExistingModuleProvider(TheModule)); + 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(new ExistingModuleProvider(TheModule)); + PerFunctionPasses->add(new TargetData(*TheTargetData)); + } + + return PerFunctionPasses; +} + +bool BackendConsumer::AddEmitPasses(bool Fast, std::string &Error) { + // 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; + } + + // FIXME: Support features? + std::string FeatureStr; + TargetMachine *TM = TME->CtorFn(*TheModule, FeatureStr); + + // Set register scheduler & allocation policy. + RegisterScheduler::setDefault(createDefaultScheduler); + RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator : + createLinearScanRegisterAllocator); + + // This is ridiculous. + // FIXME: These aren't being release for now. I'm just going to fix + // things to use raw_ostream instead. + std::ostream *AsmStdOutStream = 0; + OStream *AsmLLVMOutStream = 0; + if (OutputFile == "-" || (InputFile == "-" && OutputFile.empty())) { + AsmStdOutStream = llvm::cout.stream(); + AsmLLVMOutStream = &llvm::cout; + AsmOutStream = new raw_stdout_ostream(); + sys::Program::ChangeStdoutToBinary(); + } else { + if (OutputFile.empty()) { + llvm::sys::Path Path(InputFile); + Path.eraseSuffix(); + if (Action == Backend_EmitBC) { + Path.appendSuffix("bc"); + } else if (Action == Backend_EmitLL) { + Path.appendSuffix("ll"); + } else { + Path.appendSuffix("s"); + } + OutputFile = Path.toString(); + } + + // FIXME: raw_fd_ostream should specify its non-error condition + // better. + Error = ""; + AsmStdOutStream = new std::ofstream(OutputFile.c_str(), + (std::ios_base::binary | + std::ios_base::out)); + AsmLLVMOutStream = new OStream(AsmStdOutStream); + AsmOutStream = new raw_os_ostream(*AsmStdOutStream); + if (!Error.empty()) + return false; + } + + if (Action == Backend_EmitBC) { + getPerModulePasses()->add(CreateBitcodeWriterPass(*AsmStdOutStream)); + } else if (Action == Backend_EmitLL) { + getPerModulePasses()->add(createPrintModulePass(AsmLLVMOutStream)); + } else { + // 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(); + + // 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, Fast)) { + default: + case FileModel::Error: + Error = "Unable to interface with target machine!\n"; + return false; + case FileModel::AsmFile: + break; + } + + if (TM->addPassesToEmitFileFinish(*CodeGenPasses, 0, Fast)) { + Error = "Unable to interface with target machine!\n"; + return false; + } + } + + return true; +} + +void BackendConsumer::CreatePasses() { + +} + +/// 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; + + bool Optimize = false; // FIXME + + // Make sure IR generation is happy with the module. + // FIXME: Release this. + Module *M = Gen->ReleaseModule(); + if (!M) { + TheModule = 0; + return; + } + + assert(TheModule == M && "Unexpected module change during IR generation"); + + CreatePasses(); + + std::string Error; + if (!AddEmitPasses(!Optimize, 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) { + PerFunctionPasses->doInitialization(); + for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) + if (!I->isDeclaration()) + PerFunctionPasses->run(*I); + PerFunctionPasses->doFinalization(); + } + + if (PerModulePasses) + PerModulePasses->run(*M); + + if (CodeGenPasses) { + 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 &Features, + const std::string& InFile, + const std::string& OutFile, + bool GenerateDebugInfo) { + return new BackendConsumer(Action, Diags, Features, InFile, OutFile, + GenerateDebugInfo); +} diff --git a/Driver/Makefile b/Driver/Makefile index 3b0dae4984..3594529250 100644 --- a/Driver/Makefile +++ b/Driver/Makefile @@ -1,12 +1,19 @@ LEVEL = ../../.. +TOOLNAME = clang CPPFLAGS += -I$(PROJ_SRC_DIR)/../include CXXFLAGS = -fno-rtti -TOOLNAME = clang -USEDLIBS = clangCodeGen.a clangAnalysis.a clangRewrite.a clangSema.a \ - clangDriver.a clangAST.a clangParse.a clangLex.a clangBasic.a \ - LLVMCore.a LLVMSupport.a LLVMSystem.a \ - LLVMBitWriter.a LLVMBitReader.a LLVMCodeGen.a LLVMAnalysis.a \ - LLVMTarget.a +# Include this here so we can get the configuration of the targets +# that have been configured for construction. We have to do this +# early so we can set up LINK_COMPONENTS before including Makefile.rules +include $(LEVEL)/Makefile.config + +LINK_COMPONENTS := $(TARGETS_TO_BUILD) +USEDLIBS = clangCodeGen.a clangAnalysis.a clangRewrite.a clangSema.a \ + clangDriver.a clangAST.a clangParse.a clangLex.a \ + clangBasic.a LLVMCore.a LLVMSupport.a LLVMSystem.a \ + LLVMBitWriter.a LLVMBitReader.a LLVMSelectionDAG.a \ + LLVMCodeGen.a LLVMTransformUtils.a LLVMScalarOpts.a \ + LLVMAnalysis.a LLVMTarget.a -include $(LEVEL)/Makefile.common +include $(LLVM_SRC_ROOT)/Makefile.rules diff --git a/Driver/clang.cpp b/Driver/clang.cpp index c2afe5b622..34f6cb698e 100644 --- a/Driver/clang.cpp +++ b/Driver/clang.cpp @@ -72,6 +72,7 @@ enum ProgActions { RewriteMacros, // Expand macros but not #includes. RewriteTest, // Rewriter playground HTMLTest, // HTML displayer testing stuff. + EmitAssembly, // Emit a .s file. EmitLLVM, // Emit a .ll file. EmitBC, // Emit a .bc file. SerializeAST, // Emit a .ast file. @@ -119,6 +120,8 @@ ProgAction(llvm::cl::desc("Choose output type:"), llvm::cl::ZeroOrMore, "Build ASTs and view them with GraphViz"), clEnumValN(TestSerialization, "test-pickling", "Run prototype serialization code"), + clEnumValN(EmitAssembly, "S", + "Emit native assembly code"), clEnumValN(EmitLLVM, "emit-llvm", "Build ASTs then convert to LLVM, emit .ll file"), clEnumValN(EmitBC, "emit-llvm-bc", @@ -1103,10 +1106,15 @@ static ASTConsumer* CreateASTConsumer(const std::string& InFile, case TestSerialization: return CreateSerializationTest(Diag, FileMgr); + case EmitAssembly: + return CreateBackendConsumer(Backend_EmitAssembly, Diag, LangOpts, + InFile, OutputFile, GenerateDebugInfo); case EmitLLVM: + return CreateBackendConsumer(Backend_EmitLL, Diag, LangOpts, + InFile, OutputFile, GenerateDebugInfo); case EmitBC: - return CreateLLVMCodeGenWriter(ProgAction == EmitBC, Diag, LangOpts, - InFile, OutputFile, GenerateDebugInfo); + return CreateBackendConsumer(Backend_EmitBC, Diag, LangOpts, + InFile, OutputFile, GenerateDebugInfo); case SerializeAST: // FIXME: Allow user to tailor where the file is written. |