1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

Add first proof-of-concept universal compiler driver framework based

on ideas mentioned in PR686.
Written by Mikhail Glushenkov and contributed by Codedgers, Inc.

Old llvmc will be removed soon after new one will have all its properties.

llvm-svn: 48699
This commit is contained in:
Anton Korobeynikov 2008-03-23 08:57:20 +00:00
parent f607f27320
commit 261bddcbeb
19 changed files with 2019 additions and 3 deletions

View File

@ -222,4 +222,4 @@ namespace llvm {
} // end namespace llvm } // end namespace llvm
#endif // LLVM_ADT_INTRUSIVE_REF_CNT_PTR #endif // LLVM_ADT_INTRUSIVE_REF_CNT_PTR

View File

@ -16,7 +16,7 @@ PARALLEL_DIRS := llvm-config \
llc llvm-ranlib llvm-ar llvm-nm \ llc llvm-ranlib llvm-ar llvm-nm \
llvm-ld llvmc llvm-prof llvm-link \ llvm-ld llvmc llvm-prof llvm-link \
lli gccas gccld llvm-extract llvm-db llvm2cpp \ lli gccas gccld llvm-extract llvm-db llvm2cpp \
bugpoint llvm-bcanalyzer llvm-stub bugpoint llvm-bcanalyzer llvm-stub llvmc2
include $(LEVEL)/Makefile.config include $(LEVEL)/Makefile.config

63
tools/llvmc2/Common.td Normal file
View File

@ -0,0 +1,63 @@
//===- Tools.td - Common definitions for LLVMCC -----------*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains common definitions used in llvmcc tool description files.
//
//===----------------------------------------------------------------------===//
class Tool<list<dag> l> {
list<dag> properties = l;
}
// Possible Tool properties
def in_language;
def out_language;
def output_suffix;
def cmd_line;
def join;
def sink;
// Possible option types
def switch_option;
def parameter_option;
def parameter_list_option;
def prefix_option;
def prefix_list_option;
// Possible option properties
def append_cmd;
def forward;
def stop_compilation;
def unpack_values;
def help;
def required;
// Map from suffixes to language names
class LangToSuffixes<string str, list<string> lst> {
string lang = str;
list<string> suffixes = lst;
}
class LanguageMap<list<LangToSuffixes> lst> {
list<LangToSuffixes> map = lst;
}
// Toolchain classes
class ToolChain <list<Tool> lst> {
list <Tool> tools = lst;
}
class ToolChains <list<ToolChain> lst> {
list<ToolChain> chains = lst;
}

115
tools/llvmc2/Core.cpp Normal file
View File

@ -0,0 +1,115 @@
//===--- Core.cpp - The LLVM Compiler Driver --------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open
// Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Core driver abstractions.
//
//===----------------------------------------------------------------------===//
#include "Core.h"
#include "Utility.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CommandLine.h"
#include <algorithm>
#include <iostream>
#include <stdexcept>
using namespace llvm;
using namespace llvmcc;
extern cl::list<std::string> InputFilenames;
extern cl::opt<std::string> OutputFilename;
extern cl::opt<bool> VerboseMode;
namespace {
void print_string (const std::string& str) {
std::cerr << str << ' ';
}
}
int llvmcc::Action::Execute() {
if (VerboseMode) {
std::cerr << Command_ << " ";
std::for_each(Args_.begin(), Args_.end(), print_string);
std::cerr << '\n';
}
return ExecuteProgram(Command_, Args_);
}
int llvmcc::CompilationGraph::Build (const sys::Path& tempDir) const {
sys::Path In(InputFilenames.at(0)), Out;
// Find out which language corresponds to the suffix of the first input file
LanguageMap::const_iterator Lang = ExtsToLangs.find(In.getSuffix());
if (Lang == ExtsToLangs.end())
throw std::runtime_error("Unknown suffix!");
// Find the toolchain corresponding to this language
ToolChainMap::const_iterator ToolsIt = ToolChains.find(Lang->second);
if (ToolsIt == ToolChains.end())
throw std::runtime_error("Unknown language!");
ToolChain Tools = ToolsIt->second;
PathVector JoinList;
for (cl::list<std::string>::const_iterator B = InputFilenames.begin(),
E = InputFilenames.end(); B != E; ++B) {
In = sys::Path(*B);
// Pass input file through the toolchain
for (ToolChain::const_iterator B = Tools.begin(), E = Tools.end();
B != E; ++B) {
const Tool* CurTool = B->getPtr();
// Is this the last step in the chain?
if (llvm::next(B) == E || CurTool->IsLast()) {
JoinList.push_back(In);
break;
}
else {
Out = tempDir;
Out.appendComponent(In.getBasename());
Out.appendSuffix(CurTool->OutputSuffix());
Out.makeUnique(true, NULL);
Out.eraseFromDisk();
}
if (CurTool->GenerateAction(In, Out).Execute() != 0)
throw std::runtime_error("Tool returned error code!");
In = Out; Out.clear();
}
}
// Pass .o files to linker
const Tool* JoinNode = (--Tools.end())->getPtr();
// If the final output name is empty, set it to "a.out"
if (!OutputFilename.empty()) {
Out = sys::Path(OutputFilename);
}
else {
Out = sys::Path("a");
Out.appendSuffix(JoinNode->OutputSuffix());
}
if (JoinNode->GenerateAction(JoinList, Out).Execute() != 0)
throw std::runtime_error("Tool returned error code!");
return 0;
}
void llvmcc::Tool::UnpackValues (const std::string& from,
std::vector<std::string>& to) const {
SplitString(from, to, ",");
}

83
tools/llvmc2/Core.h Normal file
View File

@ -0,0 +1,83 @@
//===--- Core.h - The LLVM Compiler Driver ----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open
// Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Core driver abstractions.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVMCC_CORE_H
#define LLVM_TOOLS_LLVMCC_CORE_H
#include "Utility.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/System/Path.h"
#include <stdexcept>
#include <string>
#include <vector>
// Core functionality
namespace llvmcc {
typedef std::vector<llvm::sys::Path> PathVector;
typedef llvm::StringMap<std::string> LanguageMap;
class Action {
std::string Command_;
std::vector<std::string> Args_;
public:
Action (std::string const& C,
std::vector<std::string> const& A)
: Command_(C), Args_(A)
{}
int Execute();
};
class Tool : public llvm::RefCountedBaseVPTR<Tool> {
public:
virtual Action GenerateAction (PathVector const& inFiles,
llvm::sys::Path const& outFile) const = 0;
virtual Action GenerateAction (llvm::sys::Path const& inFile,
llvm::sys::Path const& outFile) const = 0;
virtual std::string Name() const = 0;
virtual std::string InputLanguage() const = 0;
virtual std::string OutputLanguage() const = 0;
virtual std::string OutputSuffix() const = 0;
virtual bool IsLast() const = 0;
virtual bool IsJoin() const = 0;
// Helper function that is called by the auto-generated code
// Splits strings of the form ",-foo,-bar,-baz"
// TOFIX: find a better name
void UnpackValues (std::string const& from,
std::vector<std::string>& to) const;
virtual ~Tool()
{}
};
typedef std::vector<llvm::IntrusiveRefCntPtr<Tool> > ToolChain;
typedef llvm::StringMap<ToolChain> ToolChainMap;
struct CompilationGraph {
ToolChainMap ToolChains;
LanguageMap ExtsToLangs;
int Build(llvm::sys::Path const& tempDir) const;
};
}
#endif // LLVM_TOOLS_LLVMCC_CORE_H

24
tools/llvmc2/Example.td Normal file
View File

@ -0,0 +1,24 @@
//===- Example.td - LLVMCC toolchain descriptions ---------*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains toolchain descriptions used by llvmcc.
//
//===----------------------------------------------------------------------===//
include "Common.td"
include "Tools.td"
// Toolchains
def ToolChains : ToolChains<[
ToolChain<[llvm_gcc_c, llc, llvm_gcc_assembler, llvm_gcc_linker]>,
ToolChain<[llvm_gcc_cpp, llc, llvm_gcc_assembler, llvm_gcc_linker]>,
ToolChain<[llvm_as, llc, llvm_gcc_assembler, llvm_gcc_linker]>,
ToolChain<[llvm_gcc_assembler, llvm_gcc_linker]>
]>;

View File

@ -0,0 +1,24 @@
//===- ExampleWithOpt.td - LLVMCC toolchain descriptions --*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains toolchain descriptions used by llvmcc.
//
//===----------------------------------------------------------------------===//
include "Common.td"
include "Tools.td"
// Toolchains
def ToolChains : ToolChains<[
ToolChain<[llvm_gcc_c, opt, llc, llvm_gcc_assembler, llvm_gcc_linker]>,
ToolChain<[llvm_gcc_cpp, opt, llc, llvm_gcc_assembler, llvm_gcc_linker]>,
ToolChain<[llvm_as, opt, llc, llvm_gcc_assembler, llvm_gcc_linker]>,
ToolChain<[llvm_gcc_assembler, llvm_gcc_linker]>
]>;

32
tools/llvmc2/Makefile Normal file
View File

@ -0,0 +1,32 @@
##===- tools/llvmcc/Makefile -------------------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open
# Source License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../..
TOOLNAME = llvmc2
BUILT_SOURCES = Tools.inc
LINK_COMPONENTS = support system
REQUIRES_EH := 1
include $(LEVEL)/Makefile.common
TOOLS_TARGET=default
ifeq ($(TOOLS_TARGET), default)
TOOLS_SOURCE=Example.td
else
TOOLS_SOURCE=ExampleWithOpt.td
endif
# TOFIX: integrate this part into Makefile.rules?
# The degree of horrorshowness in that file is too much for me atm.
$(ObjDir)/Tools.inc.tmp: $(TOOLS_SOURCE) $(ObjDir)/.dir
$(Echo) "Building LLVMCC configuration library with tblgen"
$(Verb) $(TableGen) -gen-llvmcc -o $@ $<
Tools.inc : $(ObjDir)/Tools.inc.tmp
$(Verb) $(CMP) -s $@ $< || $(CP) $< $@

28
tools/llvmc2/Tools.cpp Normal file
View File

@ -0,0 +1,28 @@
//===--- Tools.cpp - The LLVM Compiler Driver -------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open
// Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Auto-generated tool descriptions.
//
//===----------------------------------------------------------------------===//
#include "Tools.h"
#include "Core.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/Support/CommandLine.h"
#include <stdexcept>
#include <string>
#include <vector>
using namespace llvm;
using namespace llvmcc;
// Include the auto-generated file
#include "Tools.inc"

26
tools/llvmc2/Tools.h Normal file
View File

@ -0,0 +1,26 @@
//===--- Tools.h - The LLVM Compiler Driver ---------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open
// Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Auto-generated tool descriptions.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVMCC_TOOLS_H
#define LLVM_TOOLS_LLVMCC_TOOLS_H
#include "Core.h"
namespace llvmcc {
void PopulateLanguageMap(LanguageMap& language_map);
void PopulateCompilationGraph(CompilationGraph& tools);
}
#endif //LLVM_TOOLS_LLVMCC_TOOLS_H

87
tools/llvmc2/Tools.td Normal file
View File

@ -0,0 +1,87 @@
//===- Tools.td - Tools description for the LLVMCC --------*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains descriptions of the various build tools run by llvmcc.
//
//===----------------------------------------------------------------------===//
// Open issue: should we use DAG lists in Tool specifications
// or change to something like
// def LLVMGccC : < Tool<
// [ InLanguage<"c">,
// PrefixListOption<"Wl", [UnpackValues, PropertyName<Arg>, ...]>
// ...] ?
// DAG lists look more aesthetically pleasing to me.
def llvm_gcc_c : Tool<
[(in_language "c"),
(out_language "llvm-assembler"),
(output_suffix "bc"),
(cmd_line "llvm-gcc -c $INFILE -o $OUTFILE -emit-llvm"),
(sink)
]>;
def llvm_gcc_cpp : Tool<
[(in_language "c++"),
(out_language "llvm-assembler"),
(output_suffix "bc"),
(cmd_line "llvm-g++ -c $INFILE -o $OUTFILE -emit-llvm"),
(sink)
]>;
def opt : Tool<
[(in_language "llvm-bitcode"),
(out_language "llvm-bitcode"),
(output_suffix "bc"),
(cmd_line "opt $INFILE -o $OUTFILE")
]>;
def llvm_as : Tool<
[(in_language "llvm-assembler"),
(out_language "llvm-bitcode"),
(output_suffix "bc"),
(cmd_line "llvm-as $INFILE -o $OUTFILE")
]>;
def llc : Tool<
[(in_language "llvm-bitcode"),
(out_language "assembler"),
(output_suffix "s"),
(cmd_line "llc $INFILE -o $OUTFILE")
]>;
def llvm_gcc_assembler : Tool<
[(in_language "assembler"),
(out_language "object-code"),
(output_suffix "o"),
(cmd_line "llvm-gcc -c $INFILE -o $OUTFILE"),
(prefix_list_option "Wa", (unpack_values), (help "pass options to assembler"))
]>;
def llvm_gcc_linker : Tool<
[(in_language "object-code"),
(out_language "executable"),
(output_suffix "out"),
(cmd_line "llvm-gcc $INFILE -o $OUTFILE"),
(join),
(prefix_list_option "L", (forward), (help "add a directory to link path")),
(prefix_list_option "l", (forward), (help "search a library when linking")),
(prefix_list_option "Wl", (unpack_values), (help "pass options to linker"))
]>;
// Language map
def LanguageMap : LanguageMap<
[LangToSuffixes<"c++", ["cc", "cp", "cxx", "cpp", "CPP", "c++", "C"]>,
LangToSuffixes<"c", ["c"]>,
LangToSuffixes<"assembler", ["s"]>,
LangToSuffixes<"llvm-assembler", ["ll"]>,
LangToSuffixes<"llvm-bitcode", ["bc"]>,
LangToSuffixes<"object-code", ["o"]>,
LangToSuffixes<"executable", ["out"]>]>;

39
tools/llvmc2/Utility.cpp Normal file
View File

@ -0,0 +1,39 @@
//===--- Utility.cpp - The LLVM Compiler Driver -----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open
// Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Various helper and utility functions - implementation.
//
//===----------------------------------------------------------------------===//
#include "Utility.h"
#include "llvm/System/Program.h"
#include <stdexcept>
using namespace llvm;
int llvmcc::ExecuteProgram(const std::string& name,
const std::vector<std::string>& args) {
sys::Path prog = sys::Program::FindProgramByName(name);
if (prog.isEmpty())
throw std::runtime_error("Can't find program '" + name + "'");
if (!prog.canExecute())
throw std::runtime_error("Program '" + name + "' is not executable.");
// Invoke the program
std::vector<const char*> argv((args.size()+2));
argv[0] = name.c_str();
for (unsigned i = 1; i <= args.size(); ++i)
argv[i] = args[i-1].c_str();
argv[args.size()+1] = 0; // null terminate list.
return sys::Program::ExecuteAndWait(prog, &argv[0]);
}

27
tools/llvmc2/Utility.h Normal file
View File

@ -0,0 +1,27 @@
//===--- Utility.h - The LLVM Compiler Driver -------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open
// Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Various helper and utility functions.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVMCC_UTILITY_H
#define LLVM_TOOLS_LLVMCC_UTILITY_H
#include <string>
#include <vector>
namespace llvmcc {
int ExecuteProgram (const std::string& name,
const std::vector<std::string>& arguments);
}
#endif // LLVM_TOOLS_LLVMCC_UTILITY_H

View File

@ -0,0 +1,270 @@
Introduction
============
A complete rewrite of the LLVMC compiler driver is proposed, aimed at
making it more configurable and useful.
Motivation
==========
As it stands, current version of LLVMC does not meet its stated goals
of configurability and extensibility and is therefore not used
much. The need for enhancements in LLVMC is also reflected in [1]_. The
proposed rewrite will fix the aforementioned deficiences and provide
an extensible, future-proof solution.
Design
======
A compiler driver's job is essentially to find a way how to transform
a set of input files into a set of targets, depending on the
user-provided options. Since several ways of transformation can exist
potentially, it's natural to use a directed graph to represent all of
them. In this graph, nodes are tools (for example, ``gcc -S`` is a tool
that generates assembly from C language files) and edges between them
mean that the output of one tool can be given as input to another (as
in ``gcc -S -o - file.c | as``). We'll call this graph the compilation
graph.
The proposed design revolves around the compilation graph and the
following core abstractions:
- Target - An (intermediate) compilation target.
- Action - A shell command template that represents basic compilation
transformation(example: ``gcc -S $INPUT_FILE -o $OUTPUT_FILE``).
- Tool - Encapsulates information about a concrete tool used in the
compilation process, produces Actions. Operation depends on
command-line options provided by the user.
- GraphBuilder - Constructs the compilation graph, operation depends
on command-line options.
- GraphTraverser - Traverses the compilation graph and constructs a
sequence of Actions needed to build the target file, operation
depends on command-line options.
A high-level view of the compilation process:
1. Configuration libraries (see below) are loaded in and the
compilation graph is constructed from the tool descriptions.
2. Information about possible options is gathered from (the nodes of)
the compilation graph.
3. Options are parsed based on data gathered in step 2.
4. A sequence of Actions needed to build the target is constructed
using the compilation graph and provided options.
5. The resulting action sequence is executed.
Extensibility
==============
To make this design extensible, TableGen [2]_ will be used for
automatic generation of the Tool classes. Users wanting to customize
LLVMC will need to write a configuration library consisting of a set
of TableGen descriptions of compilation tools plus a number of hooks
that influence compilation graph construction and traversal. LLVMC
will have the ability to load user configuration libraries at runtime;
in fact, its own basic functionality will be implemented as a
configuration library.
TableGen specification example
------------------------------
This small example specifies a Tool that converts C source to object
files. Note that it is only a mock-up of inteded functionality, not a
final specification::
def GCC : Tool<
GCCProperties, // Properties of this tool
GCCOptions // Options description for this tool
>;
def GCCProperties : ToolProperties<[
ToolName<"GCC">,
InputLanguageName<"C">,
OutputLanguageName<"Object-Code">
InputFileExtension<"c">,
OutputFileExtension<"o">,
CommandFormat<"gcc -c $OPTIONS $FILES">
]>;
def GCCOptions : ToolOptions<[
Option<
"-Wall", // Option name
[None], // Allowed values
[AddOption<"-Wall">]>, // Action
Option<
"-Wextra", // Option name
[None], // Allowed values
[AddOption<"-Wextra">]>, // Action
Option<
"-W", // Option name
[None], // Allowed values
[AddOption<"-W">]>, // Action
Option<
"-D", // Option name
[AnyString], // Allowed values
[AddOptionWithArgument<"-D",GetOptionArgument<"-D">>]
// Action:
// If the driver was given option "-D<argument>", add
// option "-D" with the same argument to the invocation string of
// this tool.
>
]>;
Example of generated code
-------------------------
The specification above compiles to the following code (again, it's a
mock-up)::
class GCC : public Tool {
public:
GCC() { //... }
// Properties
static const char* ToolName = "GCC";
static const char* InputLanguageName = "C";
static const char* OutputLanguageName = "Object-Code";
static const char* InputFileExtension = "c";
static const char* OutputFileExtension = "o";
static const char* CommandFormat = "gcc -c $OPTIONS $FILES";
// Options
OptionsDescription SupportedOptions() {
OptionsDescription supportedOptions;
supportedOptions.Add(Option("-Wall"));
supportedOptions.Add(Option("-Wextra"));
supportedOptions.Add(Option("-W"));
supportedOptions.Add(Option("-D", AllowedArgs::ANY_STRING));
return supportedOptions;
}
Action GenerateAction(Options providedOptions) {
Action generatedAction(CommandFormat); Option curOpt;
curOpt = providedOptions.Get("-D");
if (curOpt) {
assert(curOpt.HasArgument());
generatedAction.AddOption(Option("-D", curOpt.GetArgument()));
}
curOpt = providedOptions.Get("-Wall");
if (curOpt)
generatedAction.AddOption(Option("-Wall"));
curOpt = providedOptions.Get("-Wextra");
if (curOpt)
generatedAction.AddOption(Option("-Wall"));
curOpt = providedOptions.Get("-W");
if (curOpt)
generatedAction.AddOption(Option("-Wall")); }
return generatedAction;
}
};
// defined somewhere...
class Action { public: void AddOption(const Option& opt) {...}
int Run(const Filenames& fnms) {...}
}
Option handling
===============
Since one of the main tasks of the compiler driver is to correctly
handle user-provided options, it is important to define this process
in exact way. The intent of the proposed scheme is to function as a
drop-in replacement for GCC.
Option syntax
-------------
Option syntax is specified by the following formal grammar::
<command-line> ::= <option>*
<option> ::= <positional-option> | <named-option>
<named-option> ::= -[-]<option-name>[<delimeter><option-argument>]
<delimeter> ::= ',' | '=' | ' '
<positional-option> ::= <string>
<option-name> ::= <string>
<option-argument> ::= <string>
This roughly corresponds to the GCC option syntax. Note that grouping
of short options(as in ``ls -la``) is forbidden.
Example::
llvmc -O3 -Wa,-foo,-bar -pedantic -std=c++0x a.c b.c c.c
Option arguments can also have special forms: for example, an argument
can be a comma-separated list (like in -Wa,-foo,-bar). In such cases,
it's up to the option handler to parse the argument.
Option semantics
----------------
According to their meaning, options are classified into following
categories:
- Global options - Options that influence compilation graph
construction/traversal. Example: -E (stop after preprocessing).
- Local options - Options that influence one or several Actions in
the generated action sequence. Example: -O3 (turn on optimization).
- Prefix options - Options that influence meaning of the following
command-line arguments. Example: -x language (specify language for
the input files explicitly). Prefix options can be local or global.
- Built-in options - Options that are hard-coded into
driver. Examples: --help, -o file/-pipe (redirect output). Can be
local or global.
Naming
======
Since the compiler driver, as a single point of access to the LLVM
tool set, is a very often used tool, it would be desirable to make its name
as short and easy to type as possible. Some possible names are 'llcc' or
'lcc', by analogy with gcc.
Issues
======
1. Should global-options-influencing hooks be written by hand or
auto-generated from TableGen specifications?
2. More?
References
==========
.. [1] LLVM Bug#686
http://llvm.org/bugs/show_bug.cgi?id=686
.. [2] TableGen Fundamentals
http://llvm.org/docs/TableGenFundamentals.html

View File

@ -0,0 +1,153 @@
Tutorial - Writing LLVMCC Configuration files
=============================================
LLVMCC is a generic compiler driver(just like ``gcc``), designed to be
customizable and extensible. Its job is essentially to transform a set
of input files into a set of targets, depending on configuration rules
and user options. This tutorial describes how one can write
configuration files for ``llvmcc``.
Since LLVMCC uses TableGen [1]_ as the language of its configuration
files, you need to be familiar with it.
Describing a toolchain
----------------------
The main concept that ``llvmcc`` operates with is a *toolchain*, which
is just a list of tools that process input files in a pipeline-like
fashion. Toolchain definitions look like this::
def ToolChains : ToolChains<[
ToolChain<[llvm_gcc_c, llc, llvm_gcc_assembler, llvm_gcc_linker]>,
ToolChain<[llvm_gcc_cpp, llc, llvm_gcc_assembler, llvm_gcc_linker]>,
...
]>;
Every configuration file should have a single toolchains list called
``ToolChains``.
At the time of writing, ``llvmcc`` does not support mixing various
toolchains together - in other words, all input files should be in the
same language.
Another temporary limitation is that every toolchain should end with a
"join" node - a linker-like program that combines its inputs into a
single output file.
Describing a tool
-----------------
A single element of a toolchain is a tool. A tool definition looks
like this (taken from the Tools.td file)::
def llvm_gcc_cpp : Tool<[
(in_language "c++"),
(out_language "llvm-assembler"),
(output_suffix "bc"),
(cmd_line "llvm-g++ -c $INFILE -o $OUTFILE -emit-llvm"),
(sink)
]>;
This defines a new tool called ``llvm_gcc_cpp``, which is an alias for
``llvm-g++``. As you can see, a tool definition is just a list of
properties; most of them should be self-evident. The ``sink`` property
means that this tool should be passed all command-line options that
aren't handled by the other tools.
The complete list of the currently implemented tool properties follows:
* Possible tool properties:
- in_language - input language name.
- out_language - output language name.
- output_suffix - output file suffix.
- cmd_line - the actual command used to run the tool. You can use
``$INFILE`` and ``$OUTFILE`` variables.
- join - this tool is a "join node" in the graph, i.e. it gets a
list of input files and joins them together. Used for linkers.
- sink - all command-line options that are not handled by other
tools are passed to this tool.
The next tool definition is slightly more complex::
def llvm_gcc_linker : Tool<[
(in_language "object-code"),
(out_language "executable"),
(output_suffix "out"),
(cmd_line "llvm-gcc $INFILE -o $OUTFILE"),
(join),
(prefix_list_option "L", (forward), (help "add a directory to link path")),
(prefix_list_option "l", (forward), (help "search a library when linking")),
(prefix_list_option "Wl", (unpack_values), (help "pass options to linker"))
]>;
This tool has a "join" property, which means that it behaves like a
linker (because of that this tool should be the last in the
toolchain). This tool also defines several command-line options: ``-l``,
``-L`` and ``-Wl`` which have their usual meaning. An option has two
attributes: a name and a (possibly empty) list of properties. All
currently implemented option types and properties are described below:
* Possible option types:
- switch_option - a simple boolean switch, for example ``-time``.
- parameter_option - option that takes an argument, for example ``-std=c99``;
- parameter_list_option - same as the above, but more than one
occurence of the option is allowed.
- prefix_option - same as the parameter_option, but the option name
and parameter value are not separated.
- prefix_list_option - same as the above, but more than one
occurence of the option is allowed; example: ``-lm -lpthread``.
* Possible option properties:
- append_cmd - append a string to the tool invocation command.
- forward - forward this option unchanged.
- stop_compilation - stop compilation after this phase.
- unpack_values - used for for splitting and forwarding
comma-separated lists of options, e.g. ``-Wa,-foo=bar,-baz`` is
converted to ``-foo=bar -baz`` and appended to the tool invocation
command.
- help - help string associated with this option.
- required - this option is obligatory.
Language map
------------
One last bit that you probably should change is the language map,
which defines mappings between language names and file extensions. It
is used internally to choose the proper toolchain based on the names
of the input files. Language map definition is located in the file
``Tools.td`` and looks like this::
def LanguageMap : LanguageMap<
[LangToSuffixes<"c++", ["cc", "cp", "cxx", "cpp", "CPP", "c++", "C"]>,
LangToSuffixes<"c", ["c"]>,
...
]>;
Putting it all together
-----------------------
Since at the time of writing LLVMCC does not support on-the-fly
reloading of the configuration, the only way to test your changes is
to recompile the program. To do this, ``cd`` to the source code
directory and run ``make``.
References
==========
.. [1] TableGen Fundamentals
http://llvm.cs.uiuc.edu/docs/TableGenFundamentals.html

73
tools/llvmc2/llvmcc.cpp Normal file
View File

@ -0,0 +1,73 @@
//===--- llvmcc.cpp - The LLVM Compiler Driver ------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open
// Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This tool provides a single point of access to the LLVM
// compilation tools. It has many options. To discover the options
// supported please refer to the tools' manual page or run the tool
// with the --help option.
//
//===----------------------------------------------------------------------===//
#include "Core.h"
#include "Utility.h"
#include "Tools.h"
#include "llvm/System/Path.h"
#include "llvm/Support/CommandLine.h"
#include <iostream>
#include <stdexcept>
#include <string>
using namespace llvm;
using namespace llvmcc;
// These variables are also used in Core.cpp,
// so they should have external linkage.
cl::list<std::string> InputFilenames(cl::Positional,
cl::desc("<input file>"), cl::OneOrMore);
cl::opt<std::string> OutputFilename("o", cl::desc("Output file name"),
cl::value_desc("file"));
cl::opt<bool> VerboseMode("v", cl::desc("Enable verbose mode"));
namespace {
int BuildTargets(const CompilationGraph& graph) {
int ret;
sys::Path tempDir(sys::Path::GetTemporaryDirectory());
try {
ret = graph.Build(tempDir);
}
catch(...) {
tempDir.eraseFromDisk(true);
throw;
}
tempDir.eraseFromDisk(true);
return ret;
}
}
int main(int argc, char** argv) {
try {
CompilationGraph graph;
cl::ParseCommandLineOptions(argc, argv,
"LLVM Compiler Driver(Work In Progress)");
PopulateCompilationGraph(graph);
return BuildTargets(graph);
}
catch(const std::exception& ex) {
std::cerr << ex.what() << '\n';
}
catch(...) {
std::cerr << "Unknown error!\n";
}
}

View File

@ -0,0 +1,935 @@
//===- LLVMCConfigurationEmitter.cpp - Generate LLVMCC config -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open
// Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This tablegen backend is responsible for emitting LLVMCC configuration code.
//
//===----------------------------------------------------------------------===//
#include "LLVMCCConfigurationEmitter.h"
#include "Record.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/Streams.h"
#include <algorithm>
#include <cassert>
#include <functional>
#include <string>
using namespace llvm;
namespace {
//===----------------------------------------------------------------------===//
/// Typedefs
typedef std::vector<Record*> RecordVector;
typedef std::vector<std::string> StrVector;
//===----------------------------------------------------------------------===//
/// Constants
// Indentation strings
const char * Indent1 = " ";
const char * Indent2 = " ";
const char * Indent3 = " ";
const char * Indent4 = " ";
// Default help string
const char * DefaultHelpString = "NO HELP MESSAGE PROVIDED";
// Name for the "sink" option
const char * SinkOptionName = "AutoGeneratedSinkOption";
//===----------------------------------------------------------------------===//
/// Helper functions
std::string InitPtrToString(Init* ptr) {
StringInit& val = dynamic_cast<StringInit&>(*ptr);
return val.getValue();
}
//===----------------------------------------------------------------------===//
/// Back-end specific code
// A command-line option can have one of the following types:
//
// Switch - a simple switch w/o arguments, e.g. -O2
//
// Parameter - an option that takes one(and only one) argument, e.g. -o file,
// --output=file
//
// ParameterList - same as Parameter, but more than one occurence
// of the option is allowed, e.g. -lm -lpthread
//
// Prefix - argument is everything after the prefix,
// e.g. -Wa,-foo,-bar, -DNAME=VALUE
//
// PrefixList - same as Prefix, but more than one option occurence is
// allowed
namespace OptionType {
enum OptionType { Switch, Parameter, ParameterList, Prefix, PrefixList};
}
bool IsListOptionType (OptionType::OptionType t) {
return (t == OptionType::ParameterList || t == OptionType::PrefixList);
}
// Code duplication here is necessary because one option can affect
// several tools and those tools may have different actions associated
// with this option. GlobalOptionDescriptions are used to generate
// the option registration code, while ToolOptionDescriptions are used
// to generate tool-specific code.
// Base class for option descriptions
struct OptionDescription {
OptionType::OptionType Type;
std::string Name;
OptionDescription(OptionType::OptionType t = OptionType::Switch,
const std::string& n = "")
: Type(t), Name(n)
{}
const char* GenTypeDeclaration() const {
switch (Type) {
case OptionType::PrefixList:
case OptionType::ParameterList:
return "cl::list<std::string>";
case OptionType::Switch:
return "cl::opt<bool>";
case OptionType::Parameter:
case OptionType::Prefix:
default:
return "cl::opt<std::string>";
}
}
std::string GenVariableName() const {
switch (Type) {
case OptionType::Switch:
return "AutoGeneratedSwitch" + Name;
case OptionType::Prefix:
return "AutoGeneratedPrefix" + Name;
case OptionType::PrefixList:
return "AutoGeneratedPrefixList" + Name;
case OptionType::Parameter:
return "AutoGeneratedParameter" + Name;
case OptionType::ParameterList:
default:
return "AutoGeneratedParameterList" + Name;
}
}
};
// Global option description
namespace GlobalOptionDescriptionFlags {
enum GlobalOptionDescriptionFlags { Required = 0x1 };
}
struct GlobalOptionDescription : public OptionDescription {
std::string Help;
unsigned Flags;
// StringMap can only store DefaultConstructible objects
GlobalOptionDescription() : OptionDescription(), Flags(0)
{}
GlobalOptionDescription (OptionType::OptionType t, const std::string& n)
: OptionDescription(t, n), Help(DefaultHelpString), Flags(0)
{}
bool isRequired() const {
return Flags & GlobalOptionDescriptionFlags::Required;
}
void setRequired() {
Flags |= GlobalOptionDescriptionFlags::Required;
}
// Merge two option descriptions
void Merge (const GlobalOptionDescription& other)
{
if (other.Type != Type)
throw "Conflicting definitions for the option " + Name + "!";
if (Help.empty() && !other.Help.empty())
Help = other.Help;
else if (!Help.empty() && !other.Help.empty())
cerr << "Warning: more than one help string defined for option "
+ Name + "\n";
Flags |= other.Flags;
}
};
// A GlobalOptionDescription array
// + some flags affecting generation of option declarations
struct GlobalOptionDescriptions {
typedef StringMap<GlobalOptionDescription> container_type;
typedef container_type::const_iterator const_iterator;
// A list of GlobalOptionDescriptions
container_type Descriptions;
// Should the emitter generate a "cl::sink" option?
bool HasSink;
// Support for STL-style iteration
const_iterator begin() const { return Descriptions.begin(); }
const_iterator end() const { return Descriptions.end(); }
};
// Tool-local option description
// Properties without arguments are implemented as flags
namespace ToolOptionDescriptionFlags {
enum ToolOptionDescriptionFlags { StopCompilation = 0x1,
Forward = 0x2, UnpackValues = 0x4};
}
namespace OptionPropertyType {
enum OptionPropertyType { AppendCmd };
}
typedef std::pair<OptionPropertyType::OptionPropertyType, std::string>
OptionProperty;
typedef SmallVector<OptionProperty, 4> OptionPropertyList;
struct ToolOptionDescription : public OptionDescription {
unsigned Flags;
OptionPropertyList Props;
// StringMap can only store DefaultConstructible objects
ToolOptionDescription() : OptionDescription() {}
ToolOptionDescription (OptionType::OptionType t, const std::string& n)
: OptionDescription(t, n)
{}
// Various boolean properties
bool isStopCompilation() const {
return Flags & ToolOptionDescriptionFlags::StopCompilation;
}
void setStopCompilation() {
Flags |= ToolOptionDescriptionFlags::StopCompilation;
}
bool isForward() const {
return Flags & ToolOptionDescriptionFlags::Forward;
}
void setForward() {
Flags |= ToolOptionDescriptionFlags::Forward;
}
bool isUnpackValues() const {
return Flags & ToolOptionDescriptionFlags::UnpackValues;
}
void setUnpackValues() {
Flags |= ToolOptionDescriptionFlags::UnpackValues;
}
void AddProperty (OptionPropertyType::OptionPropertyType t,
const std::string& val)
{
Props.push_back(std::make_pair(t, val));
}
};
typedef StringMap<ToolOptionDescription> ToolOptionDescriptions;
// Tool information record
namespace ToolFlags {
enum ToolFlags { Join = 0x1, Sink = 0x2 };
}
struct ToolProperties : public RefCountedBase<ToolProperties> {
std::string Name;
StrVector CmdLine;
std::string InLanguage;
std::string OutLanguage;
std::string OutputSuffix;
unsigned Flags;
ToolOptionDescriptions OptDescs;
// Various boolean properties
void setSink() { Flags |= ToolFlags::Sink; }
bool isSink() const { return Flags & ToolFlags::Sink; }
void setJoin() { Flags |= ToolFlags::Join; }
bool isJoin() const { return Flags & ToolFlags::Join; }
// Default ctor here is needed because StringMap can only store
// DefaultConstructible objects
ToolProperties() {}
ToolProperties (const std::string& n) : Name(n) {}
};
// A list of Tool information records
// IntrusiveRefCntPtrs are used because StringMap has no copy constructor
// (and we want to avoid copying ToolProperties anyway)
typedef std::vector<IntrusiveRefCntPtr<ToolProperties> > ToolPropertiesList;
// Function object for iterating over a list of tool property records
class CollectProperties {
private:
/// Implementation details
// "Property handler" - a function that extracts information
// about a given tool property from its DAG representation
typedef void (CollectProperties::*PropertyHandler)(DagInit*);
// Map from property names -> property handlers
typedef StringMap<PropertyHandler> PropertyHandlerMap;
// "Option property handler" - a function that extracts information
// about a given option property from its DAG representation
typedef void (CollectProperties::*
OptionPropertyHandler)(DagInit*, GlobalOptionDescription &);
// Map from option property names -> option property handlers
typedef StringMap<OptionPropertyHandler> OptionPropertyHandlerMap;
// Static maps from strings to CollectProperties methods("handlers")
static PropertyHandlerMap propertyHandlers_;
static OptionPropertyHandlerMap optionPropertyHandlers_;
static bool staticMembersInitialized_;
/// This is where the information is stored
// Current Tool properties
ToolProperties& toolProps_;
// OptionDescriptions table(used to register options globally)
GlobalOptionDescriptions& optDescs_;
public:
explicit CollectProperties (ToolProperties& p, GlobalOptionDescriptions& d)
: toolProps_(p), optDescs_(d)
{
if (!staticMembersInitialized_) {
// Init tool property handlers
propertyHandlers_["cmd_line"] = &CollectProperties::onCmdLine;
propertyHandlers_["in_language"] = &CollectProperties::onInLanguage;
propertyHandlers_["join"] = &CollectProperties::onJoin;
propertyHandlers_["out_language"] = &CollectProperties::onOutLanguage;
propertyHandlers_["output_suffix"] = &CollectProperties::onOutputSuffix;
propertyHandlers_["parameter_option"]
= &CollectProperties::onParameter;
propertyHandlers_["parameter_list_option"] =
&CollectProperties::onParameterList;
propertyHandlers_["prefix_option"] = &CollectProperties::onPrefix;
propertyHandlers_["prefix_list_option"] =
&CollectProperties::onPrefixList;
propertyHandlers_["sink"] = &CollectProperties::onSink;
propertyHandlers_["switch_option"] = &CollectProperties::onSwitch;
// Init option property handlers
optionPropertyHandlers_["append_cmd"] = &CollectProperties::onAppendCmd;
optionPropertyHandlers_["forward"] = &CollectProperties::onForward;
optionPropertyHandlers_["help"] = &CollectProperties::onHelp;
optionPropertyHandlers_["required"] = &CollectProperties::onRequired;
optionPropertyHandlers_["stop_compilation"] =
&CollectProperties::onStopCompilation;
optionPropertyHandlers_["unpack_values"] =
&CollectProperties::onUnpackValues;
staticMembersInitialized_ = true;
}
}
// Gets called for every tool property;
// Just forwards to the corresponding property handler.
void operator() (Init* i) {
DagInit& d = dynamic_cast<DagInit&>(*i);
std::string property_name = d.getOperator()->getAsString();
PropertyHandlerMap::iterator method
= propertyHandlers_.find(property_name);
if (method != propertyHandlers_.end()) {
PropertyHandler h = method->second;
(this->*h)(&d);
}
else {
throw "Unknown tool property: " + property_name + "!";
}
}
private:
/// Property handlers --
/// Functions that extract information about tool properties from
/// DAG representation.
void onCmdLine (DagInit* d) {
checkNumberOfArguments(d, 1);
SplitString(InitPtrToString(d->getArg(0)), toolProps_.CmdLine);
if (toolProps_.CmdLine.empty())
throw std::string("Tool " + toolProps_.Name + " has empty command line!");
}
void onInLanguage (DagInit* d) {
checkNumberOfArguments(d, 1);
toolProps_.InLanguage = InitPtrToString(d->getArg(0));
}
void onJoin (DagInit* d) {
checkNumberOfArguments(d, 0);
toolProps_.setJoin();
}
void onOutLanguage (DagInit* d) {
checkNumberOfArguments(d, 1);
toolProps_.OutLanguage = InitPtrToString(d->getArg(0));
}
void onOutputSuffix (DagInit* d) {
checkNumberOfArguments(d, 1);
toolProps_.OutputSuffix = InitPtrToString(d->getArg(0));
}
void onSink (DagInit* d) {
checkNumberOfArguments(d, 0);
optDescs_.HasSink = true;
toolProps_.setSink();
}
void onSwitch (DagInit* d) { addOption(d, OptionType::Switch); }
void onParameter (DagInit* d) { addOption(d, OptionType::Parameter); }
void onParameterList (DagInit* d) { addOption(d, OptionType::ParameterList); }
void onPrefix (DagInit* d) { addOption(d, OptionType::Prefix); }
void onPrefixList (DagInit* d) { addOption(d, OptionType::PrefixList); }
/// Option property handlers --
/// Methods that handle properties that are common for all types of
/// options (like append_cmd, stop_compilation)
void onAppendCmd (DagInit* d, GlobalOptionDescription& o) {
checkNumberOfArguments(d, 1);
std::string const& cmd = InitPtrToString(d->getArg(0));
toolProps_.OptDescs[o.Name].AddProperty(OptionPropertyType::AppendCmd, cmd);
}
void onForward (DagInit* d, GlobalOptionDescription& o) {
checkNumberOfArguments(d, 0);
toolProps_.OptDescs[o.Name].setForward();
}
void onHelp (DagInit* d, GlobalOptionDescription& o) {
checkNumberOfArguments(d, 1);
const std::string& help_message = InitPtrToString(d->getArg(0));
o.Help = help_message;
}
void onRequired (DagInit* d, GlobalOptionDescription& o) {
checkNumberOfArguments(d, 0);
o.setRequired();
}
void onStopCompilation (DagInit* d, GlobalOptionDescription& o) {
checkNumberOfArguments(d, 0);
if (o.Type != OptionType::Switch)
throw std::string("Only options of type Switch can stop compilation!");
toolProps_.OptDescs[o.Name].setStopCompilation();
}
void onUnpackValues (DagInit* d, GlobalOptionDescription& o) {
checkNumberOfArguments(d, 0);
toolProps_.OptDescs[o.Name].setUnpackValues();
}
/// Helper functions
// Add an option of type t
void addOption (DagInit* d, OptionType::OptionType t) {
checkNumberOfArguments(d, 2);
const std::string& name = InitPtrToString(d->getArg(0));
GlobalOptionDescription o(t, name);
toolProps_.OptDescs[name].Type = t;
toolProps_.OptDescs[name].Name = name;
processOptionProperties(d, o);
insertDescription(o);
}
// Ensure that the number of args in d is <= min_arguments,
// throw exception otherwise
void checkNumberOfArguments (DagInit* d, unsigned min_arguments) {
if (d->getNumArgs() < min_arguments)
throw "Property " + d->getOperator()->getAsString()
+ " has too few arguments!";
}
// Insert new GlobalOptionDescription into GlobalOptionDescriptions list
void insertDescription (const GlobalOptionDescription& o)
{
if (optDescs_.Descriptions.count(o.Name)) {
GlobalOptionDescription& D = optDescs_.Descriptions[o.Name];
D.Merge(o);
}
else {
optDescs_.Descriptions[o.Name] = o;
}
}
// Go through the list of option properties and call a corresponding
// handler for each.
//
// Parameters:
// name - option name
// d - option property list
void processOptionProperties (DagInit* d, GlobalOptionDescription& o) {
// First argument is option name
checkNumberOfArguments(d, 2);
for (unsigned B = 1, E = d->getNumArgs(); B!=E; ++B) {
DagInit& option_property
= dynamic_cast<DagInit&>(*d->getArg(B));
const std::string& option_property_name
= option_property.getOperator()->getAsString();
OptionPropertyHandlerMap::iterator method
= optionPropertyHandlers_.find(option_property_name);
if (method != optionPropertyHandlers_.end()) {
OptionPropertyHandler h = method->second;
(this->*h)(&option_property, o);
}
else {
throw "Unknown option property: " + option_property_name + "!";
}
}
}
};
// Static members of CollectProperties
CollectProperties::PropertyHandlerMap
CollectProperties::propertyHandlers_;
CollectProperties::OptionPropertyHandlerMap
CollectProperties::optionPropertyHandlers_;
bool CollectProperties::staticMembersInitialized_ = false;
// Gather information from the parsed TableGen data
// (Basically a wrapper for CollectProperties)
void CollectToolProperties (RecordVector::const_iterator B,
RecordVector::const_iterator E,
ToolPropertiesList& TPList,
GlobalOptionDescriptions& OptDescs)
{
// Iterate over a properties list of every Tool definition
for (;B!=E;++B) {
RecordVector::value_type T = *B;
ListInit* PropList = T->getValueAsListInit("properties");
if (!PropList)
throw std::string("Tool has no property list!");
IntrusiveRefCntPtr<ToolProperties>
ToolProps(new ToolProperties(T->getName()));
std::for_each(PropList->begin(), PropList->end(),
CollectProperties(*ToolProps, OptDescs));
TPList.push_back(ToolProps);
}
}
// Used by EmitGenerateActionMethod
void EmitOptionPropertyHandlingCode (const ToolProperties& P,
const ToolOptionDescription& D,
std::ostream& O)
{
// if clause
O << Indent2 << "if (";
if (D.Type == OptionType::Switch)
O << D.GenVariableName();
else
O << '!' << D.GenVariableName() << ".empty()";
O <<") {\n";
// Handle option properties that take an argument
for (OptionPropertyList::const_iterator B = D.Props.begin(),
E = D.Props.end(); B!=E; ++B) {
const OptionProperty& val = *B;
switch (val.first) {
// (append_cmd cmd) property
case OptionPropertyType::AppendCmd:
O << Indent3 << "vec.push_back(\"" << val.second << "\");\n";
break;
// Other properties with argument
default:
break;
}
}
// Handle flags
// (forward) property
if (D.isForward()) {
switch (D.Type) {
case OptionType::Switch:
O << Indent3 << "vec.push_back(\"-" << D.Name << "\");\n";
break;
case OptionType::Parameter:
O << Indent3 << "vec.push_back(\"-" << D.Name << "\");\n";
O << Indent3 << "vec.push_back(" << D.GenVariableName() << ");\n";
break;
case OptionType::Prefix:
O << Indent3 << "vec.push_back(\"-" << D.Name << "\" + "
<< D.GenVariableName() << ");\n";
break;
case OptionType::PrefixList:
O << Indent3 << "for (" << D.GenTypeDeclaration()
<< "::iterator B = " << D.GenVariableName() << ".begin(),\n"
<< Indent3 << "E = " << D.GenVariableName() << ".end(); B != E; ++B)\n"
<< Indent4 << "vec.push_back(\"-" << D.Name << "\" + "
<< "*B);\n";
break;
case OptionType::ParameterList:
O << Indent3 << "for (" << D.GenTypeDeclaration()
<< "::iterator B = " << D.GenVariableName() << ".begin(),\n"
<< Indent3 << "E = " << D.GenVariableName()
<< ".end() ; B != E; ++B) {\n"
<< Indent4 << "vec.push_back(\"-" << D.Name << "\");\n"
<< Indent4 << "vec.push_back(*B);\n"
<< Indent3 << "}\n";
break;
}
}
// (unpack_values) property
if (D.isUnpackValues()) {
if (IsListOptionType(D.Type)) {
O << Indent3 << "for (" << D.GenTypeDeclaration()
<< "::iterator B = " << D.GenVariableName() << ".begin(),\n"
<< Indent3 << "E = " << D.GenVariableName()
<< ".end(); B != E; ++B)\n"
<< Indent4 << "UnpackValues(*B, vec);\n";
}
else if (D.Type == OptionType::Prefix || D.Type == OptionType::Parameter){
O << Indent3 << "UnpackValues("
<< D.GenVariableName() << ", vec);\n";
}
else {
// TOFIX: move this to the type-checking phase
throw std::string("Switches can't have unpack_values property!");
}
}
// close if clause
O << Indent2 << "}\n";
}
// Emite one of two versions of GenerateAction method
void EmitGenerateActionMethod (const ToolProperties& P, int V, std::ostream& O)
{
assert(V==1 || V==2);
if (V==1)
O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n";
else
O << Indent1 << "Action GenerateAction(const sys::Path& inFile,\n";
O << Indent2 << "const sys::Path& outFile) const\n"
<< Indent1 << "{\n"
<< Indent2 << "std::vector<std::string> vec;\n";
// Parse CmdLine tool property
StrVector::const_iterator I = P.CmdLine.begin();
++I;
for (StrVector::const_iterator E = P.CmdLine.end(); I != E; ++I) {
const std::string& cmd = *I;
O << Indent2;
if (cmd == "$INFILE") {
if (V==1)
O << "for (PathVector::const_iterator B = inFiles.begin()"
<< ", E = inFiles.end();\n"
<< Indent2 << "B != E; ++B)\n"
<< Indent3 << "vec.push_back(B->toString());\n";
else
O << "vec.push_back(inFile.toString());\n";
}
else if (cmd == "$OUTFILE") {
O << "vec.push_back(outFile.toString());\n";
}
else {
O << "vec.push_back(\"" << cmd << "\");\n";
}
}
// For every understood option, emit handling code
for (ToolOptionDescriptions::const_iterator B = P.OptDescs.begin(),
E = P.OptDescs.end(); B != E; ++B) {
const ToolOptionDescription& val = B->second;
EmitOptionPropertyHandlingCode(P, val, O);
}
// Handle Sink property
if (P.isSink()) {
O << Indent2 << "if (!" << SinkOptionName << ".empty()) {\n"
<< Indent3 << "vec.insert(vec.end(), "
<< SinkOptionName << ".begin(), " << SinkOptionName << ".end());\n"
<< Indent2 << "}\n";
}
O << Indent2 << "return Action(\"" << P.CmdLine.at(0) << "\", vec);\n"
<< Indent1 << "}\n\n";
}
// Emit GenerateAction methods for Tool classes
void EmitGenerateActionMethods (const ToolProperties& P, std::ostream& O) {
if (!P.isJoin())
O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n"
<< Indent2 << "const llvm::sys::Path& outFile) const\n"
<< Indent1 << "{\n"
<< Indent2 << "throw std::runtime_error(\"" << P.Name
<< " is not a Join tool!\");\n"
<< Indent1 << "}\n\n";
else
EmitGenerateActionMethod(P, 1, O);
EmitGenerateActionMethod(P, 2, O);
}
// Emit IsLast() method for Tool classes
void EmitIsLastMethod (const ToolProperties& P, std::ostream& O) {
O << Indent1 << "bool IsLast() const {\n"
<< Indent2 << "bool last = false;\n";
for (ToolOptionDescriptions::const_iterator B = P.OptDescs.begin(),
E = P.OptDescs.end(); B != E; ++B) {
const ToolOptionDescription& val = B->second;
if (val.isStopCompilation())
O << Indent2
<< "if (" << val.GenVariableName()
<< ")\n" << Indent3 << "last = true;\n";
}
O << Indent2 << "return last;\n"
<< Indent1 << "}\n\n";
}
// Emit static [Input,Output]Language() methods for Tool classes
void EmitInOutLanguageMethods (const ToolProperties& P, std::ostream& O) {
O << Indent1 << "std::string InputLanguage() const {\n"
<< Indent2 << "return \"" << P.InLanguage << "\";\n"
<< Indent1 << "}\n\n";
O << Indent1 << "std::string OutputLanguage() const {\n"
<< Indent2 << "return \"" << P.OutLanguage << "\";\n"
<< Indent1 << "}\n\n";
}
// Emit static [Input,Output]Language() methods for Tool classes
void EmitOutputSuffixMethod (const ToolProperties& P, std::ostream& O) {
O << Indent1 << "std::string OutputSuffix() const {\n"
<< Indent2 << "return \"" << P.OutputSuffix << "\";\n"
<< Indent1 << "}\n\n";
}
// Emit static Name() method for Tool classes
void EmitNameMethod (const ToolProperties& P, std::ostream& O) {
O << Indent1 << "std::string Name() const {\n"
<< Indent2 << "return \"" << P.Name << "\";\n"
<< Indent1 << "}\n\n";
}
// Emit static Name() method for Tool classes
void EmitIsJoinMethod (const ToolProperties& P, std::ostream& O) {
O << Indent1 << "bool IsJoin() const {\n";
if (P.isJoin())
O << Indent2 << "return true;\n";
else
O << Indent2 << "return false;\n";
O << Indent1 << "}\n\n";
}
// Emit a Tool class definition
void EmitToolClassDefinition (const ToolProperties& P, std::ostream& O) {
// Header
O << "class " << P.Name << " : public Tool {\n"
<< "public:\n";
EmitNameMethod(P, O);
EmitInOutLanguageMethods(P, O);
EmitOutputSuffixMethod(P, O);
EmitIsJoinMethod(P, O);
EmitGenerateActionMethods(P, O);
EmitIsLastMethod(P, O);
// Close class definition
O << "};\n\n";
}
// Iterate over a list of option descriptions and emit registration code
void EmitOptionDescriptions (const GlobalOptionDescriptions& descs,
std::ostream& O)
{
// Emit static cl::Option variables
for (GlobalOptionDescriptions::const_iterator B = descs.begin(),
E = descs.end(); B!=E; ++B) {
const GlobalOptionDescription& val = B->second;
O << val.GenTypeDeclaration() << ' '
<< val.GenVariableName()
<< "(\"" << val.Name << '\"';
if (val.Type == OptionType::Prefix || val.Type == OptionType::PrefixList)
O << ", cl::Prefix";
if (val.isRequired()) {
switch (val.Type) {
case OptionType::PrefixList:
case OptionType::ParameterList:
O << ", cl::OneOrMore";
break;
default:
O << ", cl::Required";
}
}
O << ", cl::desc(\"" << val.Help << "\"));\n";
}
if (descs.HasSink)
O << "cl::list<std::string> " << SinkOptionName << "(cl::Sink);\n";
O << '\n';
}
void EmitPopulateLanguageMap (const RecordKeeper& Records, std::ostream& O)
{
// Get the relevant field out of RecordKeeper
Record* LangMapRecord = Records.getDef("LanguageMap");
if (!LangMapRecord)
throw std::string("Language map definition not found!");
ListInit* LangsToSuffixesList = LangMapRecord->getValueAsListInit("map");
if (!LangsToSuffixesList)
throw std::string("Error in the language map definition!");
// Generate code
O << "void llvmcc::PopulateLanguageMap(LanguageMap& language_map) {\n";
for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) {
Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i);
const std::string& Lang = LangToSuffixes->getValueAsString("lang");
const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes");
for (unsigned i = 0; i < Suffixes->size(); ++i)
O << Indent1 << "language_map[\""
<< InitPtrToString(Suffixes->getElement(i))
<< "\"] = \"" << Lang << "\";\n";
}
O << "}\n\n";
}
void EmitPopulateCompilationGraph (const RecordKeeper& Records,
StringMap<std::string>& ToolToLang,
std::ostream& O)
{
// Get the relevant field out of RecordKeeper
Record* ToolChains = Records.getDef("ToolChains");
if (!ToolChains)
throw std::string("No ToolChains specification found!");
ListInit* chains = ToolChains->getValueAsListInit("chains");
if (!chains)
throw std::string("Error in toolchain list definition!");
// Generate code
O << "void llvmcc::PopulateCompilationGraph(CompilationGraph& G) {\n"
<< Indent1 << "PopulateLanguageMap(G.ExtsToLangs);\n"
<< Indent1 << "std::vector<IntrusiveRefCntPtr<Tool> > vec;\n\n";
for (unsigned i = 0; i < chains->size(); ++i) {
Record* ToolChain = chains->getElementAsRecord(i);
ListInit* Tools = ToolChain->getValueAsListInit("tools");
// Get name of the first tool in the list
const std::string& firstTool =
dynamic_cast<DefInit&>(**Tools->begin()).getDef()->getName();
for (ListInit::iterator B = Tools->begin(),
E = Tools->end(); B != E; ++B) {
Record* val = dynamic_cast<DefInit&>(**B).getDef();
O << Indent1 << "vec.push_back(IntrusiveRefCntPtr<Tool>(new "
<< val->getName() << "()));\n";
}
O << Indent1 << "G.ToolChains[\"" << ToolToLang[firstTool]
<< "\"] = vec;\n";
O << Indent1 << "vec.clear();\n\n";
}
O << "}\n\n";
}
void FillInToolToLang (const ToolPropertiesList& T,
StringMap<std::string>& M) {
for (ToolPropertiesList::const_iterator B = T.begin(), E = T.end();
B != E; ++B) {
const ToolProperties& P = *(*B);
M[P.Name] = P.InLanguage;
}
}
// End of anonymous namespace
}
// Back-end entry point
void LLVMCCConfigurationEmitter::run (std::ostream &O) {
// Emit file header
EmitSourceFileHeader("LLVMCC Configuration Library", O);
// Get a list of all defined Tools
RecordVector Tools = Records.getAllDerivedDefinitions("Tool");
if (Tools.empty())
throw std::string("No tool definitions found!");
// Gather information from the Tool descriptions
ToolPropertiesList tool_props;
GlobalOptionDescriptions opt_descs;
CollectToolProperties(Tools.begin(), Tools.end(), tool_props, opt_descs);
// Emit global option registration code
EmitOptionDescriptions(opt_descs, O);
// Emit PopulateLanguageMap function
// (a language map maps from file extensions to language names)
EmitPopulateLanguageMap(Records, O);
// Emit Tool classes
for (ToolPropertiesList::const_iterator B = tool_props.begin(),
E = tool_props.end(); B!=E; ++B)
EmitToolClassDefinition(*(*B), O);
// Fill in table that maps tool names to languages
StringMap<std::string> ToolToLang;
FillInToolToLang(tool_props, ToolToLang);
// Emit PopulateCompilationGraph function
EmitPopulateCompilationGraph(Records, ToolToLang, O);
// EOF
}

View File

@ -0,0 +1,30 @@
//===- LLVMCConfigurationEmitter.cpp - Generate LLVMCC config -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open
// Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This tablegen backend is responsible for emitting LLVMCC configuration code.
//
//===----------------------------------------------------------------------===//
#ifndef LLVMCCCONF_EMITTER_H
#define LLVMCCCONF_EMITTER_H
#include "TableGenBackend.h"
namespace llvm {
class LLVMCCConfigurationEmitter : public TableGenBackend {
RecordKeeper &Records;
public:
explicit LLVMCCConfigurationEmitter(RecordKeeper &R) : Records(R) {}
// run - Output the asmwriter, returning true on failure.
void run(std::ostream &o);
};
}
#endif //LLVMCCCONF_EMITTER_H

View File

@ -31,6 +31,7 @@
#include "DAGISelEmitter.h" #include "DAGISelEmitter.h"
#include "SubtargetEmitter.h" #include "SubtargetEmitter.h"
#include "IntrinsicEmitter.h" #include "IntrinsicEmitter.h"
#include "LLVMCCConfigurationEmitter.h"
#include <algorithm> #include <algorithm>
#include <cstdio> #include <cstdio>
#include <fstream> #include <fstream>
@ -41,11 +42,12 @@ enum ActionType {
PrintRecords, PrintRecords,
GenEmitter, GenEmitter,
GenRegisterEnums, GenRegister, GenRegisterHeader, GenRegisterEnums, GenRegister, GenRegisterHeader,
GenInstrEnums, GenInstrs, GenAsmWriter, GenInstrEnums, GenInstrs, GenAsmWriter,
GenCallingConv, GenCallingConv,
GenDAGISel, GenDAGISel,
GenSubtarget, GenSubtarget,
GenIntrinsic, GenIntrinsic,
GenLLVMCCConf,
PrintEnums PrintEnums
}; };
@ -76,6 +78,8 @@ namespace {
"Generate subtarget enumerations"), "Generate subtarget enumerations"),
clEnumValN(GenIntrinsic, "gen-intrinsic", clEnumValN(GenIntrinsic, "gen-intrinsic",
"Generate intrinsic information"), "Generate intrinsic information"),
clEnumValN(GenLLVMCCConf, "gen-llvmcc",
"Generate LLVMCC configuration library"),
clEnumValN(PrintEnums, "print-enums", clEnumValN(PrintEnums, "print-enums",
"Print enum values for a class"), "Print enum values for a class"),
clEnumValEnd)); clEnumValEnd));
@ -180,6 +184,9 @@ int main(int argc, char **argv) {
case GenIntrinsic: case GenIntrinsic:
IntrinsicEmitter(Records).run(*Out); IntrinsicEmitter(Records).run(*Out);
break; break;
case GenLLVMCCConf:
LLVMCCConfigurationEmitter(Records).run(*Out);
break;
case PrintEnums: case PrintEnums:
{ {
std::vector<Record*> Recs = Records.getAllDerivedDefinitions(Class); std::vector<Record*> Recs = Records.getAllDerivedDefinitions(Class);