diff options
| author | Mikhail Glushenkov <foldr@codedgers.com> | 2008-11-25 21:38:12 +0000 |
|---|---|---|
| committer | Mikhail Glushenkov <foldr@codedgers.com> | 2008-11-25 21:38:12 +0000 |
| commit | 98d5ed5cb72e4db9cdacbfa5cdb31626729b7738 (patch) | |
| tree | 45fc6355ae8f9f2f478aa489554d96b34a5fbaef /llvm/tools/llvmc | |
| parent | 67630080b9022d0a4ef2da0f13986c876efc51ed (diff) | |
| download | bcm5719-llvm-98d5ed5cb72e4db9cdacbfa5cdb31626729b7738.tar.gz bcm5719-llvm-98d5ed5cb72e4db9cdacbfa5cdb31626729b7738.zip | |
Since the old llvmc was removed, rename llvmc2 to llvmc.
llvm-svn: 60048
Diffstat (limited to 'llvm/tools/llvmc')
26 files changed, 1829 insertions, 0 deletions
diff --git a/llvm/tools/llvmc/CMakeLists.txt b/llvm/tools/llvmc/CMakeLists.txt new file mode 100644 index 00000000000..f8204199041 --- /dev/null +++ b/llvm/tools/llvmc/CMakeLists.txt @@ -0,0 +1,4 @@ +add_subdirectory(driver) + +# TODO: support plugins and user-configured builds. +# See ./doc/LLVMC-Reference.rst "Customizing LLVMC: the compilation graph" diff --git a/llvm/tools/llvmc/Makefile b/llvm/tools/llvmc/Makefile new file mode 100644 index 00000000000..8eb35cbe9cc --- /dev/null +++ b/llvm/tools/llvmc/Makefile @@ -0,0 +1,19 @@ +##===- tools/llvmc/Makefile --------------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open +# Source License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../.. + +BUILTIN_PLUGINS = Base +DRIVER_NAME = llvmc +DIRS = plugins driver + +export BUILTIN_PLUGINS +export DRIVER_NAME + +include $(LEVEL)/Makefile.common diff --git a/llvm/tools/llvmc/doc/LLVMC-Reference.rst b/llvm/tools/llvmc/doc/LLVMC-Reference.rst new file mode 100644 index 00000000000..77d9d2bd3a4 --- /dev/null +++ b/llvm/tools/llvmc/doc/LLVMC-Reference.rst @@ -0,0 +1,517 @@ +=================================== +Customizing LLVMC: Reference Manual +=================================== +:Author: Mikhail Glushenkov <foldr@codedegers.com> + +LLVMC is a generic compiler driver, designed to be customizable and +extensible. It plays the same role for LLVM as the ``gcc`` program +does for GCC - LLVMC's job is essentially to transform a set of input +files into a set of targets depending on configuration rules and user +options. What makes LLVMC different is that these transformation rules +are completely customizable - in fact, LLVMC knows nothing about the +specifics of transformation (even the command-line options are mostly +not hard-coded) and regards the transformation structure as an +abstract graph. The structure of this graph is completely determined +by plugins, which can be either statically or dynamically linked. This +makes it possible to easily adapt LLVMC for other purposes - for +example, as a build tool for game resources. + +Because LLVMC employs TableGen [1]_ as its configuration language, you +need to be familiar with it to customize LLVMC. + + +.. contents:: + + +Compiling with LLVMC +==================== + +LLVMC tries hard to be as compatible with ``gcc`` as possible, +although there are some small differences. Most of the time, however, +you shouldn't be able to notice them:: + + $ # This works as expected: + $ llvmc -O3 -Wall hello.cpp + $ ./a.out + hello + +One nice feature of LLVMC is that one doesn't have to distinguish +between different compilers for different languages (think ``g++`` and +``gcc``) - the right toolchain is chosen automatically based on input +language names (which are, in turn, determined from file +extensions). If you want to force files ending with ".c" to compile as +C++, use the ``-x`` option, just like you would do it with ``gcc``:: + + $ # hello.c is really a C++ file + $ llvmc -x c++ hello.c + $ ./a.out + hello + +On the other hand, when using LLVMC as a linker to combine several C++ +object files you should provide the ``--linker`` option since it's +impossible for LLVMC to choose the right linker in that case:: + + $ llvmc -c hello.cpp + $ llvmc hello.o + [A lot of link-time errors skipped] + $ llvmc --linker=c++ hello.o + $ ./a.out + hello + + +Predefined options +================== + +LLVMC has some built-in options that can't be overridden in the +configuration files: + +* ``-o FILE`` - Output file name. + +* ``-x LANGUAGE`` - Specify the language of the following input files + until the next -x option. + +* ``-load PLUGIN_NAME`` - Load the specified plugin DLL. Example: + ``-load $LLVM_DIR/Release/lib/LLVMCSimple.so``. + +* ``-v`` - Enable verbose mode, i.e. print out all executed commands. + +* ``--view-graph`` - Show a graphical representation of the compilation + graph. Requires that you have ``dot`` and ``gv`` programs + installed. Hidden option, useful for debugging. + +* ``--write-graph`` - Write a ``compilation-graph.dot`` file in the + current directory with the compilation graph description in the + Graphviz format. Hidden option, useful for debugging. + +* ``--save-temps`` - Write temporary files to the current directory + and do not delete them on exit. Hidden option, useful for debugging. + +* ``--help``, ``--help-hidden``, ``--version`` - These options have + their standard meaning. + + +Compiling LLVMC plugins +======================= + +It's easiest to start working on your own LLVMC plugin by copying the +skeleton project which lives under ``$LLVMC_DIR/plugins/Simple``:: + + $ cd $LLVMC_DIR/plugins + $ cp -r Simple MyPlugin + $ cd MyPlugin + $ ls + Makefile PluginMain.cpp Simple.td + +As you can see, our basic plugin consists of only two files (not +counting the build script). ``Simple.td`` contains TableGen +description of the compilation graph; its format is documented in the +following sections. ``PluginMain.cpp`` is just a helper file used to +compile the auto-generated C++ code produced from TableGen source. It +can also contain hook definitions (see `below`__). + +__ hooks_ + +The first thing that you should do is to change the ``LLVMC_PLUGIN`` +variable in the ``Makefile`` to avoid conflicts (since this variable +is used to name the resulting library):: + + LLVMC_PLUGIN=MyPlugin + +It is also a good idea to rename ``Simple.td`` to something less +generic:: + + $ mv Simple.td MyPlugin.td + +Note that the plugin source directory must be placed under +``$LLVMC_DIR/plugins`` to make use of the existing build +infrastructure. To build a version of the LLVMC executable called +``mydriver`` with your plugin compiled in, use the following command:: + + $ cd $LLVMC_DIR + $ make BUILTIN_PLUGINS=MyPlugin DRIVER_NAME=mydriver + +To build your plugin as a dynamic library, just ``cd`` to its source +directory and run ``make``. The resulting file will be called +``LLVMC$(LLVMC_PLUGIN).$(DLL_EXTENSION)`` (in our case, +``LLVMCMyPlugin.so``). This library can be then loaded in with the +``-load`` option. Example:: + + $ cd $LLVMC_DIR/plugins/Simple + $ make + $ llvmc -load $LLVM_DIR/Release/lib/LLVMCSimple.so + +Sometimes, you will want a 'bare-bones' version of LLVMC that has no +built-in plugins. It can be compiled with the following command:: + + $ cd $LLVMC_DIR + $ make BUILTIN_PLUGINS="" + +How plugins are loaded +====================== + +It is possible for LLVMC plugins to depend on each other. For example, +one can create edges between nodes defined in some other plugin. To +make this work, however, that plugin should be loaded first. To +achieve this, the concept of plugin priority was introduced. By +default, every plugin has priority zero; to specify the priority +explicitly, put the following line in your ``.td`` file:: + + def Priority : PluginPriority<$PRIORITY_VALUE>; + # Where PRIORITY_VALUE is some integer > 0 + +Plugins are loaded in order of their (increasing) priority, starting +with 0. Therefore, the plugin with the highest priority value will be +loaded last. + + +Customizing LLVMC: the compilation graph +======================================== + +Each TableGen configuration file should include the common +definitions:: + + include "llvm/CompilerDriver/Common.td" + // And optionally: + // include "llvm/CompilerDriver/Tools.td" + // which contains some useful tool definitions. + +Internally, LLVMC stores information about possible source +transformations in form of a graph. Nodes in this graph represent +tools, and edges between two nodes represent a transformation path. A +special "root" node is used to mark entry points for the +transformations. LLVMC also assigns a weight to each edge (more on +this later) to choose between several alternative edges. + +The definition of the compilation graph (see file +``plugins/Base/Base.td`` for an example) is just a list of edges:: + + def CompilationGraph : CompilationGraph<[ + Edge<"root", "llvm_gcc_c">, + Edge<"root", "llvm_gcc_assembler">, + ... + + Edge<"llvm_gcc_c", "llc">, + Edge<"llvm_gcc_cpp", "llc">, + ... + + OptionalEdge<"llvm_gcc_c", "opt", (case (switch_on "opt"), + (inc_weight))>, + OptionalEdge<"llvm_gcc_cpp", "opt", (case (switch_on "opt"), + (inc_weight))>, + ... + + OptionalEdge<"llvm_gcc_assembler", "llvm_gcc_cpp_linker", + (case (input_languages_contain "c++"), (inc_weight), + (or (parameter_equals "linker", "g++"), + (parameter_equals "linker", "c++")), (inc_weight))>, + ... + + ]>; + +As you can see, the edges can be either default or optional, where +optional edges are differentiated by an additional ``case`` expression +used to calculate the weight of this edge. Notice also that we refer +to tools via their names (as strings). This makes it possible to add +edges to an existing compilation graph in plugins without having to +know about all tool definitions used in the graph. + +The default edges are assigned a weight of 1, and optional edges get a +weight of 0 + 2*N where N is the number of tests that evaluated to +true in the ``case`` expression. It is also possible to provide an +integer parameter to ``inc_weight`` and ``dec_weight`` - in this case, +the weight is increased (or decreased) by the provided value instead +of the default 2. + +When passing an input file through the graph, LLVMC picks the edge +with the maximum weight. To avoid ambiguity, there should be only one +default edge between two nodes (with the exception of the root node, +which gets a special treatment - there you are allowed to specify one +default edge *per language*). + +To get a visual representation of the compilation graph (useful for +debugging), run ``llvmc --view-graph``. You will need ``dot`` and +``gsview`` installed for this to work properly. + + +Writing a tool description +========================== + +As was said earlier, nodes in the compilation graph represent tools, +which are described separately. A tool definition looks like this +(taken from the ``include/llvm/CompilerDriver/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-explanatory. The ``sink`` +property means that this tool should be passed all command-line +options that lack explicit descriptions. + +The complete list of the currently implemented tool properties follows: + +* Possible tool properties: + + - ``in_language`` - input language name. Can be either a string or a + list, in case the tool supports multiple input languages. + + - ``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, output redirection + with ``>``, hook invocations (``$CALL``), environment variables + (via ``$ENV``) and the ``case`` construct (more on this below). + + - ``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. 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``. + + - ``alias_option`` - a special option type for creating + aliases. Unlike other option types, aliases are not allowed to + have any properties besides the aliased option name. Usage + example: ``(alias_option "preprocess", "E")`` + + +* Possible option properties: + + - ``append_cmd`` - append a string to the tool invocation command. + + - ``forward`` - forward this option unchanged. + + - ``forward_as`` - Change the name of this option, but forward the + argument unchanged. Example: ``(forward_as "--disable-optimize")``. + + - ``output_suffix`` - modify the output suffix of this + tool. Example: ``(switch "E", (output_suffix "i")``. + + - ``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. Used for + ``--help`` output. + + - ``required`` - this option is obligatory. + + +Option list - specifying all options in a single place +====================================================== + +It can be handy to have all information about options gathered in a +single place to provide an overview. This can be achieved by using a +so-called ``OptionList``:: + + def Options : OptionList<[ + (switch_option "E", (help "Help string")), + (alias_option "quiet", "q") + ... + ]>; + +``OptionList`` is also a good place to specify option aliases. + +Tool-specific option properties like ``append_cmd`` have (obviously) +no meaning in the context of ``OptionList``, so the only properties +allowed there are ``help`` and ``required``. + +Option lists are used at file scope. See the file +``plugins/Clang/Clang.td`` for an example of ``OptionList`` usage. + +.. _hooks: + +Using hooks and environment variables in the ``cmd_line`` property +================================================================== + +Normally, LLVMC executes programs from the system ``PATH``. Sometimes, +this is not sufficient: for example, we may want to specify tool names +in the configuration file. This can be achieved via the mechanism of +hooks - to write your own hooks, just add their definitions to the +``PluginMain.cpp`` or drop a ``.cpp`` file into the +``$LLVMC_DIR/driver`` directory. Hooks should live in the ``hooks`` +namespace and have the signature ``std::string hooks::MyHookName +(void)``. They can be used from the ``cmd_line`` tool property:: + + (cmd_line "$CALL(MyHook)/path/to/file -o $CALL(AnotherHook)") + +It is also possible to use environment variables in the same manner:: + + (cmd_line "$ENV(VAR1)/path/to/file -o $ENV(VAR2)") + +To change the command line string based on user-provided options use +the ``case`` expression (documented below):: + + (cmd_line + (case + (switch_on "E"), + "llvm-g++ -E -x c $INFILE -o $OUTFILE", + (default), + "llvm-g++ -c -x c $INFILE -o $OUTFILE -emit-llvm")) + +Conditional evaluation: the ``case`` expression +=============================================== + +The 'case' construct can be used to calculate weights of the optional +edges and to choose between several alternative command line strings +in the ``cmd_line`` tool property. It is designed after the +similarly-named construct in functional languages and takes the form +``(case (test_1), statement_1, (test_2), statement_2, ... (test_N), +statement_N)``. The statements are evaluated only if the corresponding +tests evaluate to true. + +Examples:: + + // Increases edge weight by 5 if "-A" is provided on the + // command-line, and by 5 more if "-B" is also provided. + (case + (switch_on "A"), (inc_weight 5), + (switch_on "B"), (inc_weight 5)) + + // Evaluates to "cmdline1" if option "-A" is provided on the + // command line, otherwise to "cmdline2" + (case + (switch_on "A"), "cmdline1", + (switch_on "B"), "cmdline2", + (default), "cmdline3") + +Note the slight difference in 'case' expression handling in contexts +of edge weights and command line specification - in the second example +the value of the ``"B"`` switch is never checked when switch ``"A"`` is +enabled, and the whole expression always evaluates to ``"cmdline1"`` in +that case. + +Case expressions can also be nested, i.e. the following is legal:: + + (case (switch_on "E"), (case (switch_on "o"), ..., (default), ...) + (default), ...) + +You should, however, try to avoid doing that because it hurts +readability. It is usually better to split tool descriptions and/or +use TableGen inheritance instead. + +* Possible tests are: + + - ``switch_on`` - Returns true if a given command-line switch is + provided by the user. Example: ``(switch_on "opt")``. Note that + you have to define all possible command-line options separately in + the tool descriptions. See the next section for the discussion of + different kinds of command-line options. + + - ``parameter_equals`` - Returns true if a command-line parameter equals + a given value. Example: ``(parameter_equals "W", "all")``. + + - ``element_in_list`` - Returns true if a command-line parameter list + includes a given value. Example: ``(parameter_in_list "l", "pthread")``. + + - ``input_languages_contain`` - Returns true if a given language + belongs to the current input language set. Example: + ``(input_languages_contain "c++")``. + + - ``in_language`` - Evaluates to true if the language of the input + file equals to the argument. At the moment works only with + ``cmd_line`` property on non-join nodes. Example: ``(in_language + "c++")``. + + - ``not_empty`` - Returns true if a given option (which should be + either a parameter or a parameter list) is set by the + user. Example: ``(not_empty "o")``. + + - ``default`` - Always evaluates to true. Should always be the last + test in the ``case`` expression. + + - ``and`` - A standard logical combinator that returns true iff all + of its arguments return true. Used like this: ``(and (test1), + (test2), ... (testN))``. Nesting of ``and`` and ``or`` is allowed, + but not encouraged. + + - ``or`` - Another logical combinator that returns true only if any + one of its arguments returns true. Example: ``(or (test1), + (test2), ... (testN))``. + + +Language map +============ + +One last thing that you will need to modify when adding support for a +new language to LLVMC is the language map, which defines mappings from +file extensions to language names. It is used to choose the proper +toolchain(s) for a given input file set. Language map definition looks +like this:: + + def LanguageMap : LanguageMap< + [LangToSuffixes<"c++", ["cc", "cp", "cxx", "cpp", "CPP", "c++", "C"]>, + LangToSuffixes<"c", ["c"]>, + ... + ]>; + +Debugging +========= + +When writing LLVMC plugins, it can be useful to get a visual view of +the resulting compilation graph. This can be achieved via the command +line option ``--view-graph``. This command assumes that Graphviz [2]_ and +Ghostview [3]_ are installed. There is also a ``--dump-graph`` option that +creates a Graphviz source file(``compilation-graph.dot``) in the +current directory. + + +References +========== + +.. [1] TableGen Fundamentals + http://llvm.cs.uiuc.edu/docs/TableGenFundamentals.html + +.. [2] Graphviz + http://www.graphviz.org/ + +.. [3] Ghostview + http://pages.cs.wisc.edu/~ghost/ diff --git a/llvm/tools/llvmc/doc/LLVMC-Tutorial.rst b/llvm/tools/llvmc/doc/LLVMC-Tutorial.rst new file mode 100644 index 00000000000..d41f90d6349 --- /dev/null +++ b/llvm/tools/llvmc/doc/LLVMC-Tutorial.rst @@ -0,0 +1,100 @@ +====================== +Tutorial - Using LLVMC +====================== +:Author: Mikhail Glushenkov <foldr@codedegers.com> + +LLVMC is a generic compiler driver, which plays the same role for LLVM +as the ``gcc`` program does for GCC - the difference being that LLVMC +is designed to be more adaptable and easier to customize. Most of +LLVMC functionality is implemented via plugins, which can be loaded +dynamically or compiled in. This tutorial describes the basic usage +and configuration of LLVMC. + + +.. contents:: + + +Compiling with LLVMC +==================== + +In general, LLVMC tries to be command-line compatible with ``gcc`` as +much as possible, so most of the familiar options work:: + + $ llvmc -O3 -Wall hello.cpp + $ ./a.out + hello + +This will invoke ``llvm-g++`` under the hood (you can see which +commands are executed by using the ``-v`` option). For further help on +command-line LLVMC usage, refer to the ``llvmc --help`` output. + + +Using LLVMC to generate toolchain drivers +========================================= + +LLVMC plugins are written mostly using TableGen [1]_, so you need to +be familiar with it to get anything done. + +Start by compiling ``plugins/Simple/Simple.td``, which is a primitive +wrapper for ``gcc``:: + + $ cd $LLVM_DIR/tools/llvmc + $ make DRIVER_NAME=mygcc BUILTIN_PLUGINS=Simple + $ cat > hello.c + [...] + $ mygcc hello.c + $ ./hello.out + Hello + +Here we link our plugin with the LLVMC core statically to form an +executable file called ``mygcc``. It is also possible to build our +plugin as a standalone dynamic library; this is described in the +reference manual. + +Contents of the file ``Simple.td`` look like this:: + + // Include common definitions + include "llvm/CompilerDriver/Common.td" + + // Tool descriptions + def gcc : Tool< + [(in_language "c"), + (out_language "executable"), + (output_suffix "out"), + (cmd_line "gcc $INFILE -o $OUTFILE"), + (sink) + ]>; + + // Language map + def LanguageMap : LanguageMap<[LangToSuffixes<"c", ["c"]>]>; + + // Compilation graph + def CompilationGraph : CompilationGraph<[Edge<"root", "gcc">]>; + +As you can see, this file consists of three parts: tool descriptions, +language map, and the compilation graph definition. + +At the heart of LLVMC is the idea of a compilation graph: vertices in +this graph are tools, and edges represent a transformation path +between two tools (for example, assembly source produced by the +compiler can be transformed into executable code by an assembler). The +compilation graph is basically a list of edges; a special node named +``root`` is used to mark graph entry points. + +Tool descriptions are represented as property lists: most properties +in the example above should be self-explanatory; the ``sink`` property +means that all options lacking an explicit description should be +forwarded to this tool. + +The ``LanguageMap`` associates a language name with a list of suffixes +and is used for deciding which toolchain corresponds to a given input +file. + +To learn more about LLVMC customization, refer to the reference +manual and plugin source code in the ``plugins`` directory. + +References +========== + +.. [1] TableGen Fundamentals + http://llvm.cs.uiuc.edu/docs/TableGenFundamentals.html diff --git a/llvm/tools/llvmc/doc/Makefile b/llvm/tools/llvmc/doc/Makefile new file mode 100644 index 00000000000..864376f9d90 --- /dev/null +++ b/llvm/tools/llvmc/doc/Makefile @@ -0,0 +1,21 @@ +##===- tools/llvmc/doc/Makefile ----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +RST2HTML=rst2html --stylesheet=llvm.css --link-stylesheet + +all : LLVMC-Reference.html LLVMC-Tutorial.html + +LLVMC-Tutorial.html : LLVMC-Tutorial.rst llvm.css + $(RST2HTML) $< $@ + +LLVMC-Reference.html : LLVMC-Reference.rst llvm.css + $(RST2HTML) $< $@ + +clean : + rm *.html diff --git a/llvm/tools/llvmc/doc/img/lines.gif b/llvm/tools/llvmc/doc/img/lines.gif Binary files differnew file mode 100644 index 00000000000..88f491edc30 --- /dev/null +++ b/llvm/tools/llvmc/doc/img/lines.gif diff --git a/llvm/tools/llvmc/doc/llvm.css b/llvm/tools/llvmc/doc/llvm.css new file mode 100644 index 00000000000..1c7e5cc504d --- /dev/null +++ b/llvm/tools/llvmc/doc/llvm.css @@ -0,0 +1,86 @@ +/* + * LLVM documentation style sheet + */ + +/* Common styles */ +.body { color: black; background: white; margin: 0 0 0 0 } + +/* No borders on image links */ +a:link img, a:visited img {border-style: none} + +address img { float: right; width: 88px; height: 31px; } +address { clear: right; } + +TR, TD { border: 2px solid gray; padding: 4pt 4pt 2pt 2pt; } +TH { border: 2px solid gray; font-weight: bold; font-size: 105%; + background: url("img/lines.gif"); + font-family: "Georgia,Palatino,Times,Roman,SanSerif"; text-align:center; + vertical-align: middle; } +TABLE { text-align: center; border: 2px solid black; + border-collapse: collapse; margin-top: 1em; margin-left: 1em; + margin-right: 1em; margin-bottom: 1em; } +/* + * Documentation + */ +/* Common for title and header */ +h1 { + color: black; background: url("img/lines.gif"); + font-family: "Georgia,Palatino,Times,Roman,SanSerif"; font-weight: bold; + border-width: 1px; + border-style: solid none solid none; + text-align: center; + vertical-align: middle; + padding-left: 8pt; + padding-top: 1px; + padding-bottom: 2px +} + +.doc_title { text-align: left; font-size: 25pt } +.doc_section { text-align: center; font-size: 22pt; + margin: 20pt 0pt 5pt 0pt; } +.doc_subsection { width: 75%; + text-align: left; font-size: 12pt; padding: 4pt 4pt 4pt 4pt; + margin: 1.5em 0.5em 0.5em 0.5em } + +.doc_subsubsection { margin: 2.0em 0.5em 0.5em 0.5em; + font-weight: bold; font-style: oblique; + border-bottom: 1px solid #999999; font-size: 12pt; + width: 75%; } +.doc_author { text-align: left; font-weight: bold; padding-left: 20pt } +.doc_text { text-align: left; padding-left: 20pt; padding-right: 10pt } + +.doc_footer { text-align: left; padding: 0 0 0 0 } + +.doc_hilite { color: blue; font-weight: bold; } + +.doc_table { text-align: center; width: 90%; + padding: 1px 1px 1px 1px; border: 1px; } + +.doc_table_nw { text-align: center; border: 1px; + padding: 1px 1px 1px 1px; } + +.doc_warning { color: red; font-weight: bold } + +.literal-block { border: solid 1px gray; background: #eeeeee; + margin: 0 1em 0 1em; + padding: 0 1em 0 1em; + display:table; + } +.doc_notes { background: #fafafa; border: 1px solid #cecece; padding: 0.1em } + +TABLE.layout { text-align: left; border: none; border-collapse: collapse; + padding: 4px 4px 4px 4px; } +TR.layout { border: none; padding: 4pt 4pt 2pt 2pt; } +TD.layout { border: none; padding: 4pt 4pt 2pt 2pt; + vertical-align: top;} +TD.left { border: none; padding: 4pt 4pt 2pt 2pt; text-align: left; + vertical-align: top;} +TD.right { border: none; padding: 4pt 4pt 2pt 2pt; text-align: right; + vertical-align: top;} +TH.layout { border: none; font-weight: bold; font-size: 105%; + text-align:center; vertical-align: middle; } + +/* Left align table cell */ +.td_left { border: 2px solid gray; text-align: left; } + +.toc-backref { color: black; } diff --git a/llvm/tools/llvmc/driver/Action.cpp b/llvm/tools/llvmc/driver/Action.cpp new file mode 100644 index 00000000000..c0a1b849bcd --- /dev/null +++ b/llvm/tools/llvmc/driver/Action.cpp @@ -0,0 +1,78 @@ +//===--- Action.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. +// +//===----------------------------------------------------------------------===// +// +// Action class - implementation and auxiliary functions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CompilerDriver/Action.h" + +#include "llvm/Support/CommandLine.h" +#include "llvm/System/Program.h" + +#include <iostream> +#include <stdexcept> + +using namespace llvm; +using namespace llvmc; + +extern cl::opt<bool> DryRun; +extern cl::opt<bool> VerboseMode; + +namespace { + int ExecuteProgram(const std::string& name, + const StrVector& 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."); + + // Build the command line vector and the redirects array. + const sys::Path* redirects[3] = {0,0,0}; + sys::Path stdout_redirect; + + std::vector<const char*> argv; + argv.reserve((args.size()+2)); + argv.push_back(name.c_str()); + + for (StrVector::const_iterator B = args.begin(), E = args.end(); + B!=E; ++B) { + if (*B == ">") { + ++B; + stdout_redirect.set(*B); + redirects[1] = &stdout_redirect; + } + else { + argv.push_back((*B).c_str()); + } + } + argv.push_back(0); // null terminate list. + + // Invoke the program. + return sys::Program::ExecuteAndWait(prog, &argv[0], 0, &redirects[0]); + } + + void print_string (const std::string& str) { + std::cerr << str << ' '; + } +} + +int llvmc::Action::Execute() const { + if (DryRun || VerboseMode) { + std::cerr << Command_ << " "; + std::for_each(Args_.begin(), Args_.end(), print_string); + std::cerr << '\n'; + } + if (DryRun) + return 0; + else + return ExecuteProgram(Command_, Args_); +} diff --git a/llvm/tools/llvmc/driver/CMakeLists.txt b/llvm/tools/llvmc/driver/CMakeLists.txt new file mode 100644 index 00000000000..7d4e967b73a --- /dev/null +++ b/llvm/tools/llvmc/driver/CMakeLists.txt @@ -0,0 +1,9 @@ +set(LLVM_LINK_COMPONENTS support system) +set(LLVM_REQUIRES_EH 1) + +add_llvm_tool(llvmc2 + Action.cpp + CompilationGraph.cpp + llvmc.cpp + Plugin.cpp + ) diff --git a/llvm/tools/llvmc/driver/CompilationGraph.cpp b/llvm/tools/llvmc/driver/CompilationGraph.cpp new file mode 100644 index 00000000000..81283babb48 --- /dev/null +++ b/llvm/tools/llvmc/driver/CompilationGraph.cpp @@ -0,0 +1,438 @@ +//===--- CompilationGraph.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. +// +//===----------------------------------------------------------------------===// +// +// Compilation graph - implementation. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "llvm/CompilerDriver/CompilationGraph.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/DOTGraphTraits.h" +#include "llvm/Support/GraphWriter.h" + +#include <algorithm> +#include <iterator> +#include <limits> +#include <queue> +#include <stdexcept> + +using namespace llvm; +using namespace llvmc; + +extern cl::list<std::string> InputFilenames; +extern cl::opt<std::string> OutputFilename; +extern cl::list<std::string> Languages; + +namespace llvmc { + + const std::string& LanguageMap::GetLanguage(const sys::Path& File) const { + LanguageMap::const_iterator Lang = this->find(File.getSuffix()); + if (Lang == this->end()) + throw std::runtime_error("Unknown suffix: " + File.getSuffix()); + return Lang->second; + } +} + +namespace { + + /// ChooseEdge - Return the edge with the maximum weight. + template <class C> + const Edge* ChooseEdge(const C& EdgesContainer, + const InputLanguagesSet& InLangs, + const std::string& NodeName = "root") { + const Edge* MaxEdge = 0; + unsigned MaxWeight = 0; + bool SingleMax = true; + + for (typename C::const_iterator B = EdgesContainer.begin(), + E = EdgesContainer.end(); B != E; ++B) { + const Edge* e = B->getPtr(); + unsigned EW = e->Weight(InLangs); + if (EW > MaxWeight) { + MaxEdge = e; + MaxWeight = EW; + SingleMax = true; + } else if (EW == MaxWeight) { + SingleMax = false; + } + } + + if (!SingleMax) + throw std::runtime_error("Node " + NodeName + + ": multiple maximal outward edges found!" + " Most probably a specification error."); + if (!MaxEdge) + throw std::runtime_error("Node " + NodeName + + ": no maximal outward edge found!" + " Most probably a specification error."); + return MaxEdge; + } + +} + +CompilationGraph::CompilationGraph() { + NodesMap["root"] = Node(this); +} + +Node& CompilationGraph::getNode(const std::string& ToolName) { + nodes_map_type::iterator I = NodesMap.find(ToolName); + if (I == NodesMap.end()) + throw std::runtime_error("Node " + ToolName + " is not in the graph"); + return I->second; +} + +const Node& CompilationGraph::getNode(const std::string& ToolName) const { + nodes_map_type::const_iterator I = NodesMap.find(ToolName); + if (I == NodesMap.end()) + throw std::runtime_error("Node " + ToolName + " is not in the graph!"); + return I->second; +} + +// Find the tools list corresponding to the given language name. +const CompilationGraph::tools_vector_type& +CompilationGraph::getToolsVector(const std::string& LangName) const +{ + tools_map_type::const_iterator I = ToolsMap.find(LangName); + if (I == ToolsMap.end()) + throw std::runtime_error("No tool corresponding to the language " + + LangName + " found"); + return I->second; +} + +void CompilationGraph::insertNode(Tool* V) { + if (NodesMap.count(V->Name()) == 0) + NodesMap[V->Name()] = Node(this, V); +} + +void CompilationGraph::insertEdge(const std::string& A, Edge* Edg) { + Node& B = getNode(Edg->ToolName()); + if (A == "root") { + const char** InLangs = B.ToolPtr->InputLanguages(); + for (;*InLangs; ++InLangs) + ToolsMap[*InLangs].push_back(IntrusiveRefCntPtr<Edge>(Edg)); + NodesMap["root"].AddEdge(Edg); + } + else { + Node& N = getNode(A); + N.AddEdge(Edg); + } + // Increase the inward edge counter. + B.IncrInEdges(); +} + +namespace { + sys::Path MakeTempFile(const sys::Path& TempDir, const std::string& BaseName, + const std::string& Suffix) { + sys::Path Out; + + // Make sure we don't end up with path names like '/file.o' if the + // TempDir is empty. + if (TempDir.empty()) { + Out.set(BaseName); + } + else { + Out = TempDir; + Out.appendComponent(BaseName); + } + Out.appendSuffix(Suffix); + // NOTE: makeUnique always *creates* a unique temporary file, + // which is good, since there will be no races. However, some + // tools do not like it when the output file already exists, so + // they have to be placated with -f or something like that. + Out.makeUnique(true, NULL); + return Out; + } +} + +// Pass input file through the chain until we bump into a Join node or +// a node that says that it is the last. +void CompilationGraph::PassThroughGraph (const sys::Path& InFile, + const Node* StartNode, + const InputLanguagesSet& InLangs, + const sys::Path& TempDir, + const LanguageMap& LangMap) const { + bool Last = false; + sys::Path In = InFile; + const Node* CurNode = StartNode; + + while(!Last) { + sys::Path Out; + Tool* CurTool = CurNode->ToolPtr.getPtr(); + + if (CurTool->IsJoin()) { + JoinTool& JT = dynamic_cast<JoinTool&>(*CurTool); + JT.AddToJoinList(In); + break; + } + + // Since toolchains do not have to end with a Join node, we should + // check if this Node is the last. + if (!CurNode->HasChildren() || CurTool->IsLast()) { + if (!OutputFilename.empty()) { + Out.set(OutputFilename); + } + else { + Out.set(In.getBasename()); + Out.appendSuffix(CurTool->OutputSuffix()); + } + Last = true; + } + else { + Out = MakeTempFile(TempDir, In.getBasename(), CurTool->OutputSuffix()); + } + + if (int ret = CurTool->GenerateAction(In, Out, InLangs, LangMap).Execute()) + throw error_code(ret); + + if (Last) + return; + + CurNode = &getNode(ChooseEdge(CurNode->OutEdges, + InLangs, + CurNode->Name())->ToolName()); + In = Out; Out.clear(); + } +} + +// Find the head of the toolchain corresponding to the given file. +// Also, insert an input language into InLangs. +const Node* CompilationGraph:: +FindToolChain(const sys::Path& In, const std::string* ForceLanguage, + InputLanguagesSet& InLangs, const LanguageMap& LangMap) const { + + // Determine the input language. + const std::string& InLanguage = + ForceLanguage ? *ForceLanguage : LangMap.GetLanguage(In); + + // Add the current input language to the input language set. + InLangs.insert(InLanguage); + + // Find the toolchain for the input language. + const tools_vector_type& TV = getToolsVector(InLanguage); + if (TV.empty()) + throw std::runtime_error("No toolchain corresponding to language " + + InLanguage + " found"); + return &getNode(ChooseEdge(TV, InLangs)->ToolName()); +} + +// Helper function used by Build(). +// Traverses initial portions of the toolchains (up to the first Join node). +// This function is also responsible for handling the -x option. +void CompilationGraph::BuildInitial (InputLanguagesSet& InLangs, + const sys::Path& TempDir, + const LanguageMap& LangMap) { + // This is related to -x option handling. + cl::list<std::string>::const_iterator xIter = Languages.begin(), + xBegin = xIter, xEnd = Languages.end(); + bool xEmpty = true; + const std::string* xLanguage = 0; + unsigned xPos = 0, xPosNext = 0, filePos = 0; + + if (xIter != xEnd) { + xEmpty = false; + xPos = Languages.getPosition(xIter - xBegin); + cl::list<std::string>::const_iterator xNext = llvm::next(xIter); + xPosNext = (xNext == xEnd) ? std::numeric_limits<unsigned>::max() + : Languages.getPosition(xNext - xBegin); + xLanguage = (*xIter == "none") ? 0 : &(*xIter); + } + + // For each input file: + for (cl::list<std::string>::const_iterator B = InputFilenames.begin(), + CB = B, E = InputFilenames.end(); B != E; ++B) { + sys::Path In = sys::Path(*B); + + // Code for handling the -x option. + // Output: std::string* xLanguage (can be NULL). + if (!xEmpty) { + filePos = InputFilenames.getPosition(B - CB); + + if (xPos < filePos) { + if (filePos < xPosNext) { + xLanguage = (*xIter == "none") ? 0 : &(*xIter); + } + else { // filePos >= xPosNext + // Skip xIters while filePos > xPosNext + while (filePos > xPosNext) { + ++xIter; + xPos = xPosNext; + + cl::list<std::string>::const_iterator xNext = llvm::next(xIter); + if (xNext == xEnd) + xPosNext = std::numeric_limits<unsigned>::max(); + else + xPosNext = Languages.getPosition(xNext - xBegin); + xLanguage = (*xIter == "none") ? 0 : &(*xIter); + } + } + } + } + + // Find the toolchain corresponding to this file. + const Node* N = FindToolChain(In, xLanguage, InLangs, LangMap); + // Pass file through the chain starting at head. + PassThroughGraph(In, N, InLangs, TempDir, LangMap); + } +} + +// Sort the nodes in topological order. +void CompilationGraph::TopologicalSort(std::vector<const Node*>& Out) { + std::queue<const Node*> Q; + Q.push(&getNode("root")); + + while (!Q.empty()) { + const Node* A = Q.front(); + Q.pop(); + Out.push_back(A); + for (Node::const_iterator EB = A->EdgesBegin(), EE = A->EdgesEnd(); + EB != EE; ++EB) { + Node* B = &getNode((*EB)->ToolName()); + B->DecrInEdges(); + if (B->HasNoInEdges()) + Q.push(B); + } + } +} + +namespace { + bool NotJoinNode(const Node* N) { + return N->ToolPtr ? !N->ToolPtr->IsJoin() : true; + } +} + +// Call TopologicalSort and filter the resulting list to include +// only Join nodes. +void CompilationGraph:: +TopologicalSortFilterJoinNodes(std::vector<const Node*>& Out) { + std::vector<const Node*> TopSorted; + TopologicalSort(TopSorted); + std::remove_copy_if(TopSorted.begin(), TopSorted.end(), + std::back_inserter(Out), NotJoinNode); +} + +int CompilationGraph::Build (const sys::Path& TempDir, + const LanguageMap& LangMap) { + + InputLanguagesSet InLangs; + + // Traverse initial parts of the toolchains and fill in InLangs. + BuildInitial(InLangs, TempDir, LangMap); + + std::vector<const Node*> JTV; + TopologicalSortFilterJoinNodes(JTV); + + // For all join nodes in topological order: + for (std::vector<const Node*>::iterator B = JTV.begin(), E = JTV.end(); + B != E; ++B) { + + sys::Path Out; + const Node* CurNode = *B; + JoinTool* JT = &dynamic_cast<JoinTool&>(*CurNode->ToolPtr.getPtr()); + bool IsLast = false; + + // Are there any files in the join list? + if (JT->JoinListEmpty()) + continue; + + // Is this the last tool in the toolchain? + // NOTE: we can process several toolchains in parallel. + if (!CurNode->HasChildren() || JT->IsLast()) { + if (OutputFilename.empty()) { + Out.set("a"); + Out.appendSuffix(JT->OutputSuffix()); + } + else + Out.set(OutputFilename); + IsLast = true; + } + else { + Out = MakeTempFile(TempDir, "tmp", JT->OutputSuffix()); + } + + if (int ret = JT->GenerateAction(Out, InLangs, LangMap).Execute()) + throw error_code(ret); + + if (!IsLast) { + const Node* NextNode = + &getNode(ChooseEdge(CurNode->OutEdges, InLangs, + CurNode->Name())->ToolName()); + PassThroughGraph(Out, NextNode, InLangs, TempDir, LangMap); + } + } + + return 0; +} + +// Code related to graph visualization. + +namespace llvm { + template <> + struct DOTGraphTraits<llvmc::CompilationGraph*> + : public DefaultDOTGraphTraits + { + + template<typename GraphType> + static std::string getNodeLabel(const Node* N, const GraphType&) + { + if (N->ToolPtr) + if (N->ToolPtr->IsJoin()) + return N->Name() + "\n (join" + + (N->HasChildren() ? ")" + : std::string(": ") + N->ToolPtr->OutputLanguage() + ')'); + else + return N->Name(); + else + return "root"; + } + + template<typename EdgeIter> + static std::string getEdgeSourceLabel(const Node* N, EdgeIter I) { + if (N->ToolPtr) { + return N->ToolPtr->OutputLanguage(); + } + else { + const char** InLangs = I->ToolPtr->InputLanguages(); + std::string ret; + + for (; *InLangs; ++InLangs) { + if (*(InLangs + 1)) { + ret += *InLangs; + ret += ", "; + } + else { + ret += *InLangs; + } + } + + return ret; + } + } + }; + +} + +void CompilationGraph::writeGraph() { + std::ofstream O("compilation-graph.dot"); + + if (O.good()) { + llvm::WriteGraph(this, "compilation-graph"); + O.close(); + } + else { + throw std::runtime_error("Error opening file 'compilation-graph.dot'" + " for writing!"); + } +} + +void CompilationGraph::viewGraph() { + llvm::ViewGraph(this, "compilation-graph"); +} diff --git a/llvm/tools/llvmc/driver/Error.h b/llvm/tools/llvmc/driver/Error.h new file mode 100644 index 00000000000..c0aaff1a724 --- /dev/null +++ b/llvm/tools/llvmc/driver/Error.h @@ -0,0 +1,33 @@ +//===--- Error.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. +// +//===----------------------------------------------------------------------===// +// +// Exception classes for LLVMC. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMC2_ERROR_H +#define LLVM_TOOLS_LLVMC2_ERROR_H + +#include <stdexcept> + +namespace llvmc { + + class error_code: public std::runtime_error { + int Code_; + public: + error_code (int c) + : std::runtime_error("Tool returned error code"), Code_(c) + {} + + int code() const { return Code_; } + }; + +} + +#endif //LLVM_TOOLS_LLVMC2_ERROR_H diff --git a/llvm/tools/llvmc/driver/Makefile b/llvm/tools/llvmc/driver/Makefile new file mode 100644 index 00000000000..d3aa2cd52ad --- /dev/null +++ b/llvm/tools/llvmc/driver/Makefile @@ -0,0 +1,19 @@ +##===- tools/llvmc/driver/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 = $(DRIVER_NAME) +LINK_COMPONENTS = support system +REQUIRES_EH := 1 + +ifneq ($(BUILTIN_PLUGINS),) +USEDLIBS = $(patsubst %,LLVMC%,$(BUILTIN_PLUGINS)) +endif + +include $(LEVEL)/Makefile.common diff --git a/llvm/tools/llvmc/driver/Plugin.cpp b/llvm/tools/llvmc/driver/Plugin.cpp new file mode 100644 index 00000000000..75abbd041d3 --- /dev/null +++ b/llvm/tools/llvmc/driver/Plugin.cpp @@ -0,0 +1,73 @@ +//===--- Plugin.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. +// +//===----------------------------------------------------------------------===// +// +// Plugin support. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CompilerDriver/Plugin.h" + +#include <algorithm> +#include <vector> + +namespace { + + // Registry::Add<> does not do lifetime management (probably issues + // with static constructor/destructor ordering), so we have to + // implement it here. + // + // All this static registration/life-before-main model seems + // unnecessary convoluted to me. + + static bool pluginListInitialized = false; + typedef std::vector<const llvmc::BasePlugin*> PluginList; + static PluginList Plugins; + + struct ByPriority { + bool operator()(const llvmc::BasePlugin* lhs, + const llvmc::BasePlugin* rhs) { + return lhs->Priority() < rhs->Priority(); + } + }; +} + +namespace llvmc { + + PluginLoader::PluginLoader() { + if (!pluginListInitialized) { + for (PluginRegistry::iterator B = PluginRegistry::begin(), + E = PluginRegistry::end(); B != E; ++B) + Plugins.push_back(B->instantiate()); + std::sort(Plugins.begin(), Plugins.end(), ByPriority()); + } + pluginListInitialized = true; + } + + PluginLoader::~PluginLoader() { + if (pluginListInitialized) { + for (PluginList::iterator B = Plugins.begin(), E = Plugins.end(); + B != E; ++B) + delete (*B); + } + pluginListInitialized = false; + } + + void PluginLoader::PopulateLanguageMap(LanguageMap& langMap) { + for (PluginList::iterator B = Plugins.begin(), E = Plugins.end(); + B != E; ++B) + (*B)->PopulateLanguageMap(langMap); + } + + void PluginLoader::PopulateCompilationGraph(CompilationGraph& graph) { + for (PluginList::iterator B = Plugins.begin(), E = Plugins.end(); + B != E; ++B) + (*B)->PopulateCompilationGraph(graph); + } + +} diff --git a/llvm/tools/llvmc/driver/llvmc.cpp b/llvm/tools/llvmc/driver/llvmc.cpp new file mode 100644 index 00000000000..f3a1e571926 --- /dev/null +++ b/llvm/tools/llvmc/driver/llvmc.cpp @@ -0,0 +1,119 @@ +//===--- llvmc.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 "Error.h" + +#include "llvm/CompilerDriver/CompilationGraph.h" +#include "llvm/CompilerDriver/Plugin.h" + +#include "llvm/System/Path.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/PluginLoader.h" + +#include <iostream> +#include <stdexcept> +#include <string> + +namespace cl = llvm::cl; +namespace sys = llvm::sys; +using namespace llvmc; + +// Built-in command-line options. +// External linkage here is intentional. + +cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input file>"), + cl::ZeroOrMore); +cl::opt<std::string> OutputFilename("o", cl::desc("Output file name"), + cl::value_desc("file")); +cl::list<std::string> Languages("x", + cl::desc("Specify the language of the following input files"), + cl::ZeroOrMore); +cl::opt<bool> DryRun("dry-run", + cl::desc("Only pretend to run commands")); +cl::opt<bool> VerboseMode("v", + cl::desc("Enable verbose mode")); +cl::opt<bool> WriteGraph("write-graph", + cl::desc("Write compilation-graph.dot file"), + cl::Hidden); +cl::opt<bool> ViewGraph("view-graph", + cl::desc("Show compilation graph in GhostView"), + cl::Hidden); +cl::opt<bool> SaveTemps("save-temps", + cl::desc("Keep temporary files"), + cl::Hidden); + +namespace { + /// BuildTargets - A small wrapper for CompilationGraph::Build. + int BuildTargets(CompilationGraph& graph, const LanguageMap& langMap) { + int ret; + const sys::Path& tempDir = SaveTemps + ? sys::Path("") + : sys::Path(sys::Path::GetTemporaryDirectory()); + + try { + ret = graph.Build(tempDir, langMap); + } + catch(...) { + tempDir.eraseFromDisk(true); + throw; + } + + if (!SaveTemps) + tempDir.eraseFromDisk(true); + return ret; + } +} + +int main(int argc, char** argv) { + try { + LanguageMap langMap; + CompilationGraph graph; + + cl::ParseCommandLineOptions + (argc, argv, "LLVM Compiler Driver (Work In Progress)", true); + + PluginLoader Plugins; + Plugins.PopulateLanguageMap(langMap); + Plugins.PopulateCompilationGraph(graph); + + if (WriteGraph) { + graph.writeGraph(); + if (!ViewGraph) + return 0; + } + + if (ViewGraph) { + graph.viewGraph(); + return 0; + } + + if (InputFilenames.empty()) { + throw std::runtime_error("no input files"); + } + + return BuildTargets(graph, langMap); + } + catch(llvmc::error_code& ec) { + return ec.code(); + } + catch(const std::exception& ex) { + std::cerr << argv[0] << ": " << ex.what() << '\n'; + } + catch(...) { + std::cerr << argv[0] << ": unknown error!\n"; + } + return 1; +} diff --git a/llvm/tools/llvmc/plugins/Base/Base.td b/llvm/tools/llvmc/plugins/Base/Base.td new file mode 100644 index 00000000000..85a37cb41a7 --- /dev/null +++ b/llvm/tools/llvmc/plugins/Base/Base.td @@ -0,0 +1,59 @@ +//===- Base.td - LLVMC2 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 compilation graph description used by llvmc2. +// +//===----------------------------------------------------------------------===// + +include "llvm/CompilerDriver/Common.td" +include "llvm/CompilerDriver/Tools.td" + +// Toolchains + +def CompilationGraph : CompilationGraph<[ + Edge<"root", "llvm_gcc_c">, + Edge<"root", "llvm_gcc_assembler">, + Edge<"root", "llvm_gcc_cpp">, + Edge<"root", "llvm_gcc_m">, + Edge<"root", "llvm_gcc_mxx">, + Edge<"root", "llvm_as">, + + Edge<"llvm_gcc_c", "llc">, + Edge<"llvm_gcc_cpp", "llc">, + Edge<"llvm_gcc_m", "llc">, + Edge<"llvm_gcc_mxx", "llc">, + Edge<"llvm_as", "llc">, + + OptionalEdge<"llvm_gcc_c", "opt", (case (switch_on "opt"), (inc_weight))>, + OptionalEdge<"llvm_gcc_cpp", "opt", (case (switch_on "opt"), (inc_weight))>, + OptionalEdge<"llvm_gcc_m", "opt", (case (switch_on "opt"), (inc_weight))>, + OptionalEdge<"llvm_gcc_mxx", "opt", (case (switch_on "opt"), (inc_weight))>, + OptionalEdge<"llvm_as", "opt", (case (switch_on "opt"), (inc_weight))>, + Edge<"opt", "llc">, + + Edge<"llc", "llvm_gcc_assembler">, + Edge<"llvm_gcc_assembler", "llvm_gcc_linker">, + OptionalEdge<"llvm_gcc_assembler", "llvm_gcc_cpp_linker", + (case + (or (input_languages_contain "c++"), + (input_languages_contain "objective-c++")), + (inc_weight), + (or (parameter_equals "linker", "g++"), + (parameter_equals "linker", "c++")), (inc_weight))>, + + + Edge<"root", "llvm_gcc_linker">, + OptionalEdge<"root", "llvm_gcc_cpp_linker", + (case + (or (input_languages_contain "c++"), + (input_languages_contain "objective-c++")), + (inc_weight), + (or (parameter_equals "linker", "g++"), + (parameter_equals "linker", "c++")), (inc_weight))> + ]>; diff --git a/llvm/tools/llvmc/plugins/Base/Makefile b/llvm/tools/llvmc/plugins/Base/Makefile new file mode 100644 index 00000000000..5ca6048508a --- /dev/null +++ b/llvm/tools/llvmc/plugins/Base/Makefile @@ -0,0 +1,13 @@ +##===- tools/llvmc/plugins/Base/Makefile -------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLVMC_PLUGIN = Base +BUILT_SOURCES = AutoGenerated.inc + +include ../Makefile diff --git a/llvm/tools/llvmc/plugins/Base/PluginMain.cpp b/llvm/tools/llvmc/plugins/Base/PluginMain.cpp new file mode 100644 index 00000000000..add8acb4a57 --- /dev/null +++ b/llvm/tools/llvmc/plugins/Base/PluginMain.cpp @@ -0,0 +1 @@ +#include "AutoGenerated.inc" diff --git a/llvm/tools/llvmc/plugins/Clang/Clang.td b/llvm/tools/llvmc/plugins/Clang/Clang.td new file mode 100644 index 00000000000..0f5d8cd9180 --- /dev/null +++ b/llvm/tools/llvmc/plugins/Clang/Clang.td @@ -0,0 +1,85 @@ +// A (first stab at a) replacement for the Clang's ccc script. +// To compile, use this command: +// cd $LLVMC2_DIR +// make DRIVER_NAME=ccc2 BUILTIN_PLUGINS=Clang + +include "llvm/CompilerDriver/Common.td" + + +def Options : OptionList<[ +(switch_option "E", + (help "Stop after the preprocessing stage, do not run the compiler")) +]>; + +class clang_base<string language, dag cmdline> : Tool< +[(in_language language), + (out_language "llvm-bitcode"), + (output_suffix "bc"), + (cmd_line cmdline), + (switch_option "E", (stop_compilation), (output_suffix "i")), + (sink) +]>; + +def clang_c : clang_base<"c", +(case +(switch_on "E"), + (case + (not_empty "o"), + "clang -E -x c $INFILE -o $OUTFILE", + (default), + "clang -E -x c $INFILE"), +(default), + "clang -emit-llvm-bc -x c $INFILE -o $OUTFILE")>; + +def clang_cpp : clang_base<"c++", +(case +(switch_on "E"), + (case + (not_empty "o"), + "clang -E -x c++ $INFILE -o $OUTFILE", + (default), + "clang -E -x c++ $INFILE"), +(default), + "clang -emit-llvm-bc -x c++ $INFILE -o $OUTFILE")>; + +def clang_objective_c : clang_base<"objective-c", +(case +(switch_on "E"), + (case + (not_empty "o"), + "clang -E -x objective-c $INFILE -o $OUTFILE", + (default), + "clang -E -x objective-c $INFILE"), +(default), + "clang -emit-llvm-bc -x objective-c $INFILE -o $OUTFILE")>; + +// Default linker +def llvm_ld : Tool< +[(in_language "llvm-bitcode"), + (out_language "executable"), + (output_suffix "out"), + (cmd_line "llvm-ld -native -disable-internalize $INFILE -o $OUTFILE"), + (prefix_list_option "L", (forward), (help "Specify a library search path")), + (join) +]>; + +// Language map + +def LanguageMap : LanguageMap< + [LangToSuffixes<"c++", ["cc", "cp", "cxx", "cpp", "CPP", "c++", "C"]>, + LangToSuffixes<"c", ["c"]>, + LangToSuffixes<"objective-c", ["m"]>, + LangToSuffixes<"c-cpp-output", ["i"]>, + LangToSuffixes<"objective-c-cpp-output", ["mi"]> + ]>; + +// Compilation graph + +def CompilationGraph : CompilationGraph<[ + Edge<"root", "clang_c">, + Edge<"root", "clang_cpp">, + Edge<"root", "clang_objective_c">, + Edge<"clang_c", "llvm_ld">, + Edge<"clang_cpp", "llvm_ld">, + Edge<"clang_objective_c", "llvm_ld"> + ]>; diff --git a/llvm/tools/llvmc/plugins/Clang/Makefile b/llvm/tools/llvmc/plugins/Clang/Makefile new file mode 100644 index 00000000000..32060138c23 --- /dev/null +++ b/llvm/tools/llvmc/plugins/Clang/Makefile @@ -0,0 +1,13 @@ +##===- tools/llvmc/plugins/Clang/Makefile ------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLVMC_PLUGIN = Clang +BUILT_SOURCES = AutoGenerated.inc + +include ../Makefile diff --git a/llvm/tools/llvmc/plugins/Clang/PluginMain.cpp b/llvm/tools/llvmc/plugins/Clang/PluginMain.cpp new file mode 100644 index 00000000000..add8acb4a57 --- /dev/null +++ b/llvm/tools/llvmc/plugins/Clang/PluginMain.cpp @@ -0,0 +1 @@ +#include "AutoGenerated.inc" diff --git a/llvm/tools/llvmc/plugins/Hello/Hello.cpp b/llvm/tools/llvmc/plugins/Hello/Hello.cpp new file mode 100644 index 00000000000..2ecd2f1c5b9 --- /dev/null +++ b/llvm/tools/llvmc/plugins/Hello/Hello.cpp @@ -0,0 +1,30 @@ +//===- Hello.cpp - Example code from "Writing an LLVM Pass" ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Test plugin for LLVMC. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CompilerDriver/CompilationGraph.h" +#include "llvm/CompilerDriver/Plugin.h" + +#include <iostream> + +namespace { +struct MyPlugin : public llvmc::BasePlugin { + void PopulateLanguageMap(llvmc::LanguageMap&) const + { std::cout << "Hello!\n"; } + + void PopulateCompilationGraph(llvmc::CompilationGraph&) const + {} +}; + +static llvmc::RegisterPlugin<MyPlugin> RP("Hello", "Hello World plugin"); + +} diff --git a/llvm/tools/llvmc/plugins/Hello/Makefile b/llvm/tools/llvmc/plugins/Hello/Makefile new file mode 100644 index 00000000000..181dd0c6050 --- /dev/null +++ b/llvm/tools/llvmc/plugins/Hello/Makefile @@ -0,0 +1,12 @@ +##===- tools/llvmc/plugins/Hello/Makefile ------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLVMC_PLUGIN = Hello + +include ../Makefile diff --git a/llvm/tools/llvmc/plugins/Makefile b/llvm/tools/llvmc/plugins/Makefile new file mode 100644 index 00000000000..dab58e07581 --- /dev/null +++ b/llvm/tools/llvmc/plugins/Makefile @@ -0,0 +1,55 @@ +##===- tools/llvmc/plugins/Makefile.plugins ----------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open +# Source License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +ifndef LLVMC_PLUGIN + +LEVEL = ../../.. +DIRS = $(BUILTIN_PLUGINS) + +# TOFIX: Should we also build DSO versions of plugins? +export BUILTIN_LLVMC_PLUGIN=1 + +include $(LEVEL)/Makefile.common + +else # LLVMC_PLUGIN + +LEVEL = ../../../.. + +LIBRARYNAME := $(patsubst %,LLVMC%,$(LLVMC_PLUGIN)) +REQUIRES_EH = 1 + +ifndef BUILTIN_LLVMC_PLUGIN +LOADABLE_MODULE = 1 +endif + +ifneq ($(BUILT_SOURCES),) +BUILD_AUTOGENERATED_INC=1 +endif + +include $(LEVEL)/Makefile.common + +# TOFIX: This probably should go into Makefile.rules + +ifdef BUILD_AUTOGENERATED_INC + +TOOLS_SOURCE := $(strip $(wildcard $(PROJ_SRC_DIR)/*.td)) + +TD_COMMON :=$(strip $(wildcard \ + $(LLVM_SRC_ROOT)/include/llvm/CompilerDriver/*.td)) + +$(ObjDir)/AutoGenerated.inc.tmp: $(TOOLS_SOURCE) $(ObjDir)/.dir \ + $(TBLGEN) $(TD_COMMON) + $(Echo) "Building LLVMC configuration library with tblgen" + $(Verb) $(TableGen) -gen-llvmc -o $(call SYSPATH, $@) $< + +AutoGenerated.inc : $(ObjDir)/AutoGenerated.inc.tmp + $(Verb) $(CMP) -s $@ $< || $(CP) $< $@ +endif # BUILD_AUTOGENERATED_INC + +endif # LLVMC_PLUGIN diff --git a/llvm/tools/llvmc/plugins/Simple/Makefile b/llvm/tools/llvmc/plugins/Simple/Makefile new file mode 100644 index 00000000000..1cd5af7a15e --- /dev/null +++ b/llvm/tools/llvmc/plugins/Simple/Makefile @@ -0,0 +1,13 @@ +##===- tools/llvmc/plugins/Simple/Makefile -----------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLVMC_PLUGIN = Simple +BUILT_SOURCES = AutoGenerated.inc + +include ../Makefile diff --git a/llvm/tools/llvmc/plugins/Simple/PluginMain.cpp b/llvm/tools/llvmc/plugins/Simple/PluginMain.cpp new file mode 100644 index 00000000000..add8acb4a57 --- /dev/null +++ b/llvm/tools/llvmc/plugins/Simple/PluginMain.cpp @@ -0,0 +1 @@ +#include "AutoGenerated.inc" diff --git a/llvm/tools/llvmc/plugins/Simple/Simple.td b/llvm/tools/llvmc/plugins/Simple/Simple.td new file mode 100644 index 00000000000..b974cbc95eb --- /dev/null +++ b/llvm/tools/llvmc/plugins/Simple/Simple.td @@ -0,0 +1,30 @@ +// A simple wrapper for gcc. +// To compile, use this command: +// +// $ cd $LLVMC2_DIR +// $ make DRIVER_NAME=mygcc BUILTIN_PLUGINS=Simple +// +// To build this plugin as a dynamic library: +// +// $ cd $LLVMC2_DIR +// $ make BUILTIN_PLUGINS="" +// $ cd plugins/Simple +// $ make +// +// Run as: +// +// $ llvmc2 -load $LLVM_DIR/Release/lib/LLVMCSimple.so + +include "llvm/CompilerDriver/Common.td" + +def gcc : Tool< +[(in_language "c"), + (out_language "executable"), + (output_suffix "out"), + (cmd_line "gcc $INFILE -o $OUTFILE"), + (sink) +]>; + +def LanguageMap : LanguageMap<[LangToSuffixes<"c", ["c"]>]>; + +def CompilationGraph : CompilationGraph<[Edge<"root", "gcc">]>; |

