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
This commit is contained in:
Daniel Dunbar 2009-03-13 11:38:42 +00:00
Родитель 3279575a37
Коммит ad2a9af666
3 изменённых файлов: 110 добавлений и 38 удалений

Просмотреть файл

@ -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")

Просмотреть файл

@ -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);

Просмотреть файл

@ -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 {