From ad2a9af666efdd9afe3bb5f886bcb0d1c9a0f0c3 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Fri, 13 Mar 2009 11:38:42 +0000 Subject: [PATCH] Driver: Complete "pipelining" (building the list of abstract actions to perform). Still doesn't do anything interesting. - This code came out much cleaner than in ccc with the reworked phases & mapping of types to lists of compilation steps (phases) to perform. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66885 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticDriverKinds.def | 3 + include/clang/Driver/Driver.h | 26 ++-- lib/Driver/Driver.cpp | 119 +++++++++++++++--- 3 files changed, 110 insertions(+), 38 deletions(-) diff --git a/include/clang/Basic/DiagnosticDriverKinds.def b/include/clang/Basic/DiagnosticDriverKinds.def index e832504bfa..006bd34eb6 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.def +++ b/include/clang/Basic/DiagnosticDriverKinds.def @@ -28,3 +28,6 @@ DIAG(err_drv_no_input_files, ERROR, "no input files") DIAG(err_drv_use_of_Z_option, ERROR, "unsupported use of internal gcc -Z option '%0'") + +DIAG(warn_drv_input_file_unused, WARNING, + "%0: '%1' input file unused when '%2' is present") diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h index 0b549cf845..7385f11ddc 100644 --- a/include/clang/Driver/Driver.h +++ b/include/clang/Driver/Driver.h @@ -12,6 +12,7 @@ #include "clang/Basic/Diagnostic.h" +#include "clang/Driver/Phases.h" #include "clang/Driver/Util.h" #include "llvm/System/Path.h" // FIXME: Kill when CompilationInfo @@ -32,25 +33,6 @@ namespace driver { /// Driver - Encapsulate logic for constructing compilation processes /// from a set of gcc-driver-like command line arguments. class Driver { - /// PhaseOrder - Ordered values for successive stages in the - /// compilation process which interact with user options. - enum PhaseOrder { - /// Nothing. - NoPhaseOrder = 0, - - /// Only run the preprocessor. - PreprocessPhaseOrder, - - /// Only run the preprocessor and compiler. - CompilePhaseOrder, - - /// Only run the preprocessor, compiler, and assembler. - AssemblePhaseOrder, - - /// Run everything. - PostAssemblePhaseOrder - }; - OptTable *Opts; Diagnostic &Diags; @@ -184,6 +166,12 @@ public: /// invocation. bool HandleImmediateArgs(const ArgList &Args); + /// ConstructAction - Construct the appropriate action to do for + /// \arg Phase on the \arg Input, taking in to account arguments + /// like -fsyntax-only or --analyze. + Action *ConstructPhaseAction(const ArgList &Args, phases::ID Phase, + Action *Input) const; + /// GetHostInfo - Construct a new host info object for the given /// host triple. static HostInfo *GetHostInfo(const char *HostTriple); diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 4fc03ce765..75e9df25e0 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -43,6 +43,8 @@ Driver::~Driver() { ArgList *Driver::ParseArgStrings(const char **ArgBegin, const char **ArgEnd) { ArgList *Args = new ArgList(ArgBegin, ArgEnd); + // FIXME: Handle '@' args (or at least error on them). + unsigned Index = 0, End = ArgEnd - ArgBegin; while (Index < End) { // gcc's handling of empty arguments doesn't make @@ -393,43 +395,122 @@ void Driver::BuildActions(ArgList &Args, ActionList &Actions) { // Determine which compilation mode we are in. We look for options // which affect the phase, starting with the earliest phases, and // record which option we used to determine the final phase. - Arg *FinalPhaseOpt = 0; - PhaseOrder FinalPhase; + Arg *FinalPhaseArg = 0; + phases::ID FinalPhase; // -{E,M,MM} only run the preprocessor. - if ((FinalPhaseOpt = Args.getLastArg(options::OPT_E)) || - (FinalPhaseOpt = Args.getLastArg(options::OPT_M)) || - (FinalPhaseOpt = Args.getLastArg(options::OPT_MM))) { - FinalPhase = PreprocessPhaseOrder; + if ((FinalPhaseArg = Args.getLastArg(options::OPT_E)) || + (FinalPhaseArg = Args.getLastArg(options::OPT_M)) || + (FinalPhaseArg = Args.getLastArg(options::OPT_MM))) { + FinalPhase = phases::Preprocess; // -{-analyze,fsyntax-only,S} only run up to the compiler. - } else if ((FinalPhaseOpt = Args.getLastArg(options::OPT__analyze)) || - (FinalPhaseOpt = Args.getLastArg(options::OPT_fsyntax_only)) || - (FinalPhaseOpt = Args.getLastArg(options::OPT_S))) { - FinalPhase = CompilePhaseOrder; + } else if ((FinalPhaseArg = Args.getLastArg(options::OPT__analyze)) || + (FinalPhaseArg = Args.getLastArg(options::OPT_fsyntax_only)) || + (FinalPhaseArg = Args.getLastArg(options::OPT_S))) { + FinalPhase = phases::Compile; // -c only runs up to the assembler. - } else if ((FinalPhaseOpt = Args.getLastArg(options::OPT_c))) { - FinalPhase = AssemblePhaseOrder; + } else if ((FinalPhaseArg = Args.getLastArg(options::OPT_c))) { + FinalPhase = phases::Assemble; // Otherwise do everything. } else - FinalPhase = PostAssemblePhaseOrder; + FinalPhase = phases::Link; - if (FinalPhaseOpt) - FinalPhaseOpt->claim(); + if (FinalPhaseArg) + FinalPhaseArg->claim(); // Reject -Z* at the top level, these options should never have been // exposed by gcc. if (Arg *A = Args.getLastArg(options::OPT_Z)) Diag(clang::diag::err_drv_use_of_Z_option) << A->getValue(Args); - // FIXME: This is just debugging code. + // Construct the actions to perform. + ActionList LinkerInputs; for (unsigned i = 0, e = Inputs.size(); i != e; ++i) { - llvm::errs() << "input " << i << ": " - << Inputs[i].second->getValue(Args) << "\n"; + types::ID InputType = Inputs[i].first; + const Arg *InputArg = Inputs[i].second; + + unsigned NumSteps = types::getNumCompilationPhases(InputType); + assert(NumSteps && "Invalid number of steps!"); + + // If the first step comes after the final phase we are doing as + // part of this compilation, warn the user about it. + phases::ID InitialPhase = types::getCompilationPhase(InputType, 0); + if (InitialPhase > FinalPhase) { + Diag(clang::diag::warn_drv_input_file_unused) + << InputArg->getValue(Args) + << getPhaseName(InitialPhase) + << FinalPhaseArg->getOption().getName(); + continue; + } + + // Build the pipeline for this file. + Action *Current = new InputAction(*InputArg, InputType); + for (unsigned i = 0; i != NumSteps; ++i) { + phases::ID Phase = types::getCompilationPhase(InputType, i); + + // We are done if this step is past what the user requested. + if (Phase > FinalPhase) + break; + + // Queue linker inputs. + if (Phase == phases::Link) { + assert(i + 1 == NumSteps && "linking must be final compilation step."); + LinkerInputs.push_back(Current); + Current = 0; + break; + } + + // Otherwise construct the appropriate action. + Current = ConstructPhaseAction(Args, Phase, Current); + if (Current->getType() == types::TY_Nothing) + break; + } + + // If we ended with something, add to the output list. + if (Current) + Actions.push_back(Current); } - exit(0); + + // Add a link action if necessary. + if (!LinkerInputs.empty()) + Actions.push_back(new LinkJobAction(LinkerInputs, types::TY_Image)); +} + +Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, + Action *Input) const { + // Build the appropriate action. + switch (Phase) { + case phases::Link: assert(0 && "link action invalid here."); + case phases::Preprocess: { + types::ID OutputTy = types::getPreprocessedType(Input->getType()); + assert(OutputTy != types::TY_INVALID && + "Cannot preprocess this input type!"); + return new PreprocessJobAction(Input, OutputTy); + } + case phases::Precompile: + return new PrecompileJobAction(Input, types::TY_PCH); + case phases::Compile: { + if (Args.hasArg(options::OPT_fsyntax_only)) { + return new CompileJobAction(Input, types::TY_Nothing); + } else if (Args.hasArg(options::OPT__analyze)) { + return new AnalyzeJobAction(Input, types::TY_Plist); + } else if (Args.hasArg(options::OPT_emit_llvm)) { + types::ID Output = + Args.hasArg(options::OPT_S) ? types::TY_LLVMAsm : types::TY_LLVMBC; + return new CompileJobAction(Input, Output); + } else { + return new CompileJobAction(Input, types::TY_PP_Asm); + } + } + case phases::Assemble: + return new AssembleJobAction(Input, types::TY_Object); + } + + assert(0 && "invalid phase in ConstructPhaseAction"); + return 0; } llvm::sys::Path Driver::GetFilePath(const char *Name) const { -- 2.40.0