├── .clang-format
├── CMakeLists.txt
├── Info.plist.in
├── LICENSE.TXT
├── Makefile
├── README.md
├── include
├── PrintableTemplightEntries.h
├── TemplightAction.h
├── TemplightDebugger.h
├── TemplightEntryPrinter.h
├── TemplightProtobufWriter.h
├── TemplightTracer.h
└── ThinProtobuf.h
├── lib
├── CMakeLists.txt
├── TemplightAction.cpp
├── TemplightDebugger.cpp
├── TemplightEntryPrinter.cpp
├── TemplightProtobufWriter.cpp
└── TemplightTracer.cpp
├── templight_clang_patch.diff
├── templight_clang_patch_with_context.diff
├── templight_clang_version.txt
├── templight_driver.cpp
├── templight_messages.proto
├── templight_symlink.cmake
├── test
├── CMakeLists.txt
├── Unit
│ ├── lit.cfg.py
│ └── lit.site.cfg.py.in
├── lit.cfg
├── lit.site.cfg.in
├── templight-driver-flag.cpp
└── templight_as_compiler.cpp
├── unittests
├── CMakeLists.txt
└── TemplightActionTest.cpp
└── utils
├── ExtraWriters
├── TemplightExtraWriters.cpp
└── TemplightExtraWriters.h
├── ProtobufReader
├── TemplightProtobufReader.cpp
└── TemplightProtobufReader.h
├── create_patch.sh
└── format.sh
/.clang-format:
--------------------------------------------------------------------------------
1 | BasedOnStyle: LLVM
2 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 | set( LLVM_LINK_COMPONENTS
3 | ${LLVM_TARGETS_TO_BUILD}
4 | Analysis
5 | CodeGen
6 | Core
7 | IPO
8 | InstCombine
9 | Instrumentation
10 | MC
11 | MCParser
12 | ObjCARCOpts
13 | Option
14 | ScalarOpts
15 | Support
16 | TargetParser
17 | TransformUtils
18 | Vectorize
19 | )
20 |
21 | include_directories(BEFORE
22 | ${CMAKE_CURRENT_SOURCE_DIR}/include
23 | )
24 | add_subdirectory(lib)
25 |
26 | add_clang_executable(templight
27 | templight_driver.cpp
28 | )
29 |
30 | target_link_libraries(templight
31 | PRIVATE
32 | clangBasic
33 | clangDriver
34 | clangFrontend
35 | clangFrontendTool
36 | clangSerialization
37 | clangTemplight
38 | )
39 |
40 | set_target_properties(templight PROPERTIES VERSION ${CLANG_EXECUTABLE_VERSION})
41 |
42 | add_dependencies(templight clang-headers)
43 |
44 | if(UNIX)
45 | set(CLANGXX_LINK_OR_COPY create_symlink)
46 | # Create a relative symlink
47 | set(templight_binary "templight${CMAKE_EXECUTABLE_SUFFIX}")
48 | else()
49 | set(CLANGXX_LINK_OR_COPY copy)
50 | set(templight_binary "${LLVM_RUNTIME_OUTPUT_INTDIR}/templight${CMAKE_EXECUTABLE_SUFFIX}")
51 | endif()
52 |
53 | # Create the templight++ symlink in the build directory.
54 | set(templight_pp "${LLVM_RUNTIME_OUTPUT_INTDIR}/templight++${CMAKE_EXECUTABLE_SUFFIX}")
55 | add_custom_command(TARGET templight POST_BUILD
56 | COMMAND ${CMAKE_COMMAND} -E ${CLANGXX_LINK_OR_COPY} "${templight_binary}" "${templight_pp}"
57 | WORKING_DIRECTORY "${LLVM_RUNTIME_OUTPUT_INTDIR}")
58 |
59 | set_property(DIRECTORY APPEND
60 | PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${templight_pp})
61 |
62 | # Create the templight-cl symlink in the build directory.
63 | set(templight_cl "${LLVM_RUNTIME_OUTPUT_INTDIR}/templight-cl${CMAKE_EXECUTABLE_SUFFIX}")
64 | add_custom_command(TARGET templight POST_BUILD
65 | COMMAND ${CMAKE_COMMAND} -E ${CLANGXX_LINK_OR_COPY} "${templight_binary}" "${templight_cl}"
66 | WORKING_DIRECTORY "${LLVM_RUNTIME_OUTPUT_INTDIR}")
67 |
68 | set_property(DIRECTORY APPEND
69 | PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${templight_cl})
70 |
71 | install(TARGETS templight
72 | RUNTIME DESTINATION bin)
73 |
74 | # Create the templight-cl symlinks at installation time.
75 | install(SCRIPT templight_symlink.cmake -DCMAKE_INSTALL_PREFIX=\"${CMAKE_INSTALL_PREFIX}\")
76 |
77 | # Configure plist creation for OS X.
78 | set (TOOL_INFO_PLIST "Info.plist" CACHE STRING "Plist name")
79 | if (APPLE)
80 | if (CLANG_VENDOR)
81 | set(TOOL_INFO_NAME "${CLANG_VENDOR} templight")
82 | else()
83 | set(TOOL_INFO_NAME "templight")
84 | endif()
85 |
86 | set(TOOL_INFO_UTI "${CLANG_VENDOR_UTI}")
87 | set(TOOL_INFO_VERSION "${CLANG_VERSION}")
88 | if (LLVM_SUBMIT_VERSION)
89 | set(TOOL_INFO_BUILD_VERSION
90 | "${LLVM_SUBMIT_VERSION}.${LLVM_SUBMIT_SUBVERSION}")
91 | endif()
92 |
93 | set(TOOL_INFO_PLIST_OUT "${CMAKE_CURRENT_BINARY_DIR}/${TOOL_INFO_PLIST}")
94 | target_link_libraries(templight
95 | PRIVATE
96 | "-Wl,-sectcreate,__TEXT,__info_plist,${TOOL_INFO_PLIST_OUT}")
97 | configure_file("${TOOL_INFO_PLIST}.in" "${TOOL_INFO_PLIST_OUT}" @ONLY)
98 |
99 | set(TOOL_INFO_UTI)
100 | set(TOOL_INFO_NAME)
101 | set(TOOL_INFO_VERSION)
102 | set(TOOL_INFO_BUILD_VERSION)
103 | endif()
104 |
105 | if(CLANG_ORDER_FILE)
106 | target_link_libraries(templight PRIVATE "-Wl,-order_file,${CLANG_ORDER_FILE}")
107 | endif()
108 |
109 | if(WITH_POLLY AND LINK_POLLY_INTO_TOOLS)
110 | target_link_libraries(templight PRIVATE Polly)
111 | if(POLLY_LINK_LIBS)
112 | foreach(lib ${POLLY_LINK_LIBS})
113 | target_link_libraries(templight PRIVATE ${lib})
114 | endforeach(lib)
115 | endif(POLLY_LINK_LIBS)
116 | endif(WITH_POLLY AND LINK_POLLY_INTO_TOOLS)
117 |
118 | set(TEMPLIGHT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
119 | set(TEMPLIGHT_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}")
120 |
121 | if(CLANG_INCLUDE_TESTS)
122 | add_subdirectory(test)
123 | add_subdirectory(unittests)
124 | endif()
125 |
--------------------------------------------------------------------------------
/Info.plist.in:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleIdentifier
6 | @TOOL_INFO_UTI@
7 | CFBundleInfoDictionaryVersion
8 | 6.0
9 | CFBundleName
10 | @TOOL_INFO_NAME
11 | CFBundleShortVersionString
12 | @TOOL_INFO_VERSION@
13 | CFBundleVersion
14 | @TOOL_INFO_BUILD_VERSION@
15 | CFBundleSignature
16 | ????
17 |
18 |
19 |
--------------------------------------------------------------------------------
/LICENSE.TXT:
--------------------------------------------------------------------------------
1 | ==============================================================================
2 | LLVM Release License
3 | ==============================================================================
4 | University of Illinois/NCSA
5 | Open Source License
6 |
7 | Copyright (c) 2007-2014 University of Illinois at Urbana-Champaign.
8 | All rights reserved.
9 |
10 | Developed by:
11 |
12 | LLVM Team
13 |
14 | University of Illinois at Urbana-Champaign
15 |
16 | http://llvm.org
17 |
18 | Permission is hereby granted, free of charge, to any person obtaining a copy of
19 | this software and associated documentation files (the "Software"), to deal with
20 | the Software without restriction, including without limitation the rights to
21 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
22 | of the Software, and to permit persons to whom the Software is furnished to do
23 | so, subject to the following conditions:
24 |
25 | * Redistributions of source code must retain the above copyright notice,
26 | this list of conditions and the following disclaimers.
27 |
28 | * Redistributions in binary form must reproduce the above copyright notice,
29 | this list of conditions and the following disclaimers in the
30 | documentation and/or other materials provided with the distribution.
31 |
32 | * Neither the names of the LLVM Team, University of Illinois at
33 | Urbana-Champaign, nor the names of its contributors may be used to
34 | endorse or promote products derived from this Software without specific
35 | prior written permission.
36 |
37 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
39 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
40 | CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
43 | SOFTWARE.
44 |
45 | ==============================================================================
46 | The LLVM software contains code written by third parties. Such software will
47 | have its own individual LICENSE.TXT file in the directory in which it appears.
48 | This file will describe the copyrights, license, and restrictions which apply
49 | to that code.
50 |
51 | The disclaimer of warranty in the University of Illinois Open Source License
52 | applies to all code in the LLVM Distribution, and nothing in any of the
53 | other licenses gives permission to use the names of the LLVM Team or the
54 | University of Illinois to endorse or promote products derived from this
55 | Software.
56 |
57 | The following pieces of software have additional or alternate copyrights,
58 | licenses, and/or restrictions:
59 |
60 | Program Directory
61 | ------- ---------
62 |
63 |
64 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | ##===- tools/templight/Makefile ----------------------------*- Makefile -*-===##
2 | #
3 | # The LLVM Compiler Infrastructure
4 | #
5 | # This file is distributed under the University of Illinois Open Source
6 | # License. See LICENSE.TXT for details.
7 | #
8 | ##===----------------------------------------------------------------------===##
9 | CLANG_LEVEL := ../..
10 |
11 | TOOLNAME = templight
12 | TOOLALIAS = templight++
13 |
14 | ifdef CLANG_ORDER_FILE
15 | TOOL_ORDER_FILE := $(CLANG_ORDER_FILE)
16 | endif
17 |
18 | # Include tool version information on OS X.
19 | TOOL_INFO_PLIST := Info.plist
20 |
21 | # Include this here so we can get the configuration of the targets that have
22 | # been configured for construction. We have to do this early so we can set up
23 | # LINK_COMPONENTS before including Makefile.rules
24 | include $(CLANG_LEVEL)/../../Makefile.config
25 |
26 | # Have the option of not supporting plugins. This is important for startup
27 | # performance.
28 | ifeq ($(CLANG_PLUGIN_SUPPORT), 1)
29 | NO_DEAD_STRIP := 1
30 | else
31 | TOOL_NO_EXPORTS := 1
32 | endif
33 |
34 | LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader bitwriter codegen \
35 | instrumentation ipo irreader linker objcarcopts option \
36 | profiledata selectiondag
37 | USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
38 | clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
39 | clangRewriteFrontend.a clangRewrite.a
40 |
41 | ifeq ($(ENABLE_CLANG_STATIC_ANALYZER),1)
42 | USEDLIBS += clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
43 | clangStaticAnalyzerCore.a
44 | endif
45 |
46 | ifeq ($(ENABLE_CLANG_ARCMT),1)
47 | USEDLIBS += clangARCMigrate.a
48 | endif
49 |
50 | USEDLIBS += clangAnalysis.a clangEdit.a clangAST.a clangLex.a clangBasic.a
51 |
52 | include $(CLANG_LEVEL)/Makefile
53 |
54 | # Set the tool version information values.
55 | ifeq ($(HOST_OS),Darwin)
56 | ifdef CLANG_VENDOR
57 | TOOL_INFO_NAME := $(CLANG_VENDOR) templight
58 | else
59 | TOOL_INFO_NAME := templight
60 | endif
61 |
62 | ifdef CLANG_VENDOR_UTI
63 | TOOL_INFO_UTI := $(CLANG_VENDOR_UTI)
64 | else
65 | TOOL_INFO_UTI := org.llvm.clang
66 | endif
67 |
68 | TOOL_INFO_VERSION := $(word 3,$(shell grep "CLANG_VERSION " \
69 | $(PROJ_OBJ_DIR)/$(CLANG_LEVEL)/include/clang/Basic/Version.inc))
70 | ifdef LLVM_SUBMIT_VERSION
71 | TOOL_INFO_BUILD_VERSION := $(LLVM_SUBMIT_VERSION).$(LLVM_SUBMIT_SUBVERSION)
72 | else
73 | TOOL_INFO_BUILD_VERSION :=
74 | endif
75 | endif
76 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Templight 2.0 - Template Instantiation Profiler and Debugger
2 |
3 | Templight is a Clang-based tool to profile the time and memory consumption of template instantiations and to perform interactive debugging sessions to gain introspection into the template instantiation process.
4 |
5 | **Disclaimer**: Templight is still at a very preliminary state. We hope to get as much early adoption and testing as we can get, but be aware that we are still experimenting with the output formats and some of the behaviors.
6 |
7 | ## Table of Contents
8 |
9 | - [Templight Profiler](#templight-profiler)
10 | - [Templight Debugger](#templight-debugger)
11 | - [Getting Started](#getting-started)
12 | - [Getting and Compiling Templight](#getting-and-compiling-templight)
13 | - [Invoking Templight](#invoking-templight)
14 | - [Using the Templight Profiler](#using-the-templight-profiler)
15 | - [Default Output Location](#default-output-location)
16 | - [Using the Templight Debugger](#using-the-templight-debugger)
17 | - [Using Blacklists](#using-blacklists)
18 | - [Inspecting the profiles](#inspecting-the-profiles)
19 | - [Credits](#credits)
20 |
21 | ## Templight Profiler
22 |
23 | The templight profiler is intended to be used as a drop-in substitute for the clang compiler (or one of its variants, like clang-cl) and it performs a full compilation, *honoring all the clang compiler options*, but records a trace (or history) of the template instantiations performed by the compiler for each translation unit.
24 |
25 | The profiler will record a time-stamp when a template instantiation is entered and when it is exited, which is what forms the compilation-time profile of the template instantiations of a translation unit. The total memory consumption can also be recorded at these points, which will skew the time profiles, but provide a profile of the memory consumed by the compiler during the template instantiations.
26 |
27 | The profiler is enabled by the templight option `-profiler`, and it supports the following additional templight options:
28 |
29 | - `-stdout` - Output template instantiation traces to standard output (mainly for piping / redirecting purposes). Warning: you need to make sure the source files compile cleanly, otherwise, the output will be corrupted by warning or error messages.
30 | - `-memory` - Profile the memory usage during template instantiations.
31 | - `-safe-mode` - Output Templight traces without buffering, not to lose them at failure (note: this will distort the timing profiles due to file I/O latency).
32 | - `-ignore-system` - Ignore any template instantiation located in system-includes (-isystem), such as from the STL.
33 | - `-output=` - Write Templight profiling traces to . By default, it outputs to "current_source.cpp.trace.pbf" or "current_source.cpp.memory.trace.pbf" (if `-memory` is used).
34 | - `-blacklist=` - Specify a blacklist file that lists declaration contexts (e.g., namespaces) and identifiers (e.g., `std::basic_string`) as regular expressions to be filtered out of the trace (not appear in the profiler trace files). Every line of the blacklist file should contain either "context" or "identifier", followed by a single space character and then, a valid regular expression.
35 |
36 | ## Templight Debugger
37 |
38 | The templight interactive debugger is also a drop-in substitute for the clang compiler, honoring all its options, but it will interrupt the compilation with a console prompt (stdin). The operations of the templight debugger are modeled after the GDB debugger and essentially works the same, *with most commands being the same*, but instead of stepping through the execution of the code (in GDB), it steps through the instantiation of the templates.
39 |
40 | In short, the templight debugger is to template meta-programming what GDB is to regular code.
41 |
42 | The debugger is enabled by the templight option `-debugger`, and it supports the following additional templight options:
43 |
44 | - `-ignore-system` - Ignore any template instantiation located in system-includes (-isystem), such as from the STL.
45 | - `-blacklist=` - Specify a blacklist file that lists declaration contexts (e.g., namespaces) and identifiers (e.g., `std::basic_string`) as regular expressions to be ignored by the debugger. Every line of the blacklist file should contain either "context" or "identifier", followed by a single space character and then, a valid regular expression.
46 |
47 | **NOTE**: Both the debugger and the profiler **can be used together**. Obviously, if compilation is constantly interrupted by the interactive debugger, the time traces recorded by the profiler will be meaningless. Nevertheless, running the profiler during debugging will have the benefit of recording the history of the template instantiations, for later review, and can also record, with reasonably accuracy, the memory consumption profiles.
48 |
49 | ## Getting Started
50 |
51 | ### Getting and Compiling Templight
52 |
53 | Templight must be compiled from source, alongside the Clang source code.
54 |
55 | 1. [Follow the instructions from LLVM/Clang](http://clang.llvm.org/get_started.html) to get a local copy of the Clang source code.
56 |
57 | 2. Clone the templight repository into the clang directories, as follows:
58 | ```bash
59 | (from top-level folder)
60 | $ cd clang/tools
61 | $ mkdir templight
62 | $ git clone templight
63 | ```
64 |
65 | 3. Add the `templight` subdirectory to CMake:
66 | ```bash
67 | (from top-level folder)
68 | $ cd clang/tools
69 | $ echo "add_clang_subdirectory(templight)" >> CMakeLists.txt
70 | ```
71 |
72 | 4. (Re-)Compile LLVM / Clang: (same as the corresponding step in LLVM/Clang instructions)
73 | ```bash
74 | (from top-level folder)
75 | $ mkdir build
76 | $ cd build
77 | $ cmake -DLLVM_ENABLE_PROJECTS=clang ../llvm/
78 | $ make
79 | ```
80 |
81 | 5. If successful, there should be a `templight` and a `templight++` executable in the build/bin folder.
82 |
83 | **NOTE**: You do not need to apply the patch `templight_clang_patch.diff` and you can ignore the corresponding
84 | version numbers in `templight_clang_version.txt`. Those are meant for other uses case (testing some hooks within clang).
85 |
86 |
87 | ### Invoking Templight
88 |
89 | Templight is designed to be a drop-in replacement for the clang compiler. This is because in order to correctly profile the compilation, it must run as the compiler would, honoring all compilation options specified by the user.
90 |
91 | Because of this particular situation, the options for templight must be specially marked with `-Xtemplight` to distinguish them from other Clang options. The general usage goes like this:
92 |
93 | ```bash
94 | $ templight++ [[-Xtemplight [templight-option]]|[clang-option]]
95 | ```
96 |
97 | Or, for the MSVC-compatible version of templight (analoguous to clang-cl) use as follows:
98 |
99 | ```bash
100 | $ templight-cl [[-Xtemplight [templight-option]]|[clang-option]]
101 | (OR)
102 | > templight-cl.exe [[-Xtemplight [templight-option]]|[clang-option]]
103 | ```
104 |
105 | For example, if we have this simple command-line invocation of clang:
106 |
107 | ```bash
108 | $ clang++ -Wall -c some_source.cpp -o some_source.o
109 | ```
110 |
111 | The corresponding templight profiler invocation, with options `-memory` and `-ignore-system` would look like this:
112 |
113 | ```bash
114 | $ templight++ -Xtemplight -profiler -Xtemplight -memory -Xtemplight -ignore-system -Wall -c some_source.cpp -o some_source.o
115 | ```
116 |
117 | Note that the order in which the templight-options appear is not important, and that clang options can be interleaved with templight-options. However, **every single templight-option must be immediately preceeded with `-Xtemplight`**.
118 |
119 | As can be seen from that simple example, one can easily substitude the clang command (e.g., `clang++`) with a compound templight invocation (e.g., `templight++ -Xtemplight -profiler -Xtemplight -memory`) and thus, leave the remainder of the command-line intact. That is how templight can be used as a drop-in replacement for clang in any given project, build script or an IDE's build configuration.
120 |
121 | If you use CMake and Clang with the following common trick:
122 | ```bash
123 | $ export CC=/path/to/llvm/build/bin/clang
124 | $ export CXX=/path/to/llvm/build/bin/clang++
125 | $ cmake
126 | ```
127 | Then, templight could be swapped in by the same trick:
128 | ```bash
129 | $ export CC="/path/to/llvm/build/bin/templight -Xtemplight -profiler -Xtemplight -memory"
130 | $ export CXX="/path/to/llvm/build/bin/templight++ -Xtemplight -profiler -Xtemplight -memory"
131 | $ cmake
132 | ```
133 | But be warned that the **cmake scripts will not fully recognize this compiler**, and therefore, you might have to make small changes in the CMake files to be able to handle it. Up to now, experience with building complete cmake projects with templight has been very successful as cmake essentially recognizes templight as a "Clang" compiler and applies the appropriate configuration. There were, however, a few minor issues found that were easily circumvented on a case-by-case basis, and so, be warned that this might not work perfectly on the first try. If anyone is interested in creating some CMake modules to deal with templight specifically, please contact the maintainer, such modules would be more than welcomed. Also, any feedback on your experience working with templight on a large project would be much appreciated.
134 |
135 | ## Using the Templight Profiler
136 |
137 | The templight profiler is invoked by specifying the templight-option `-profiler`. By default, if no other templight-option is specified, the templight profiler will output only time profiling data and will output to one file per input source file and will append the extension `.trace.pbf` to the output filename (object file output).
138 |
139 | For example, running the following:
140 | ```bash
141 | $ templight++ -Xtemplight -profiler -c some_source.cpp
142 | ```
143 | will produce a file called `some_source.o.trace.pbf` in the same directory as `some_source.cpp`.
144 |
145 | It is, in general, highly recommended to use the `-ignore-system` option for the profiler (and debugger too) because instantiations from standard or third-party libraries can cause significant noise and dramatically increase the size of the trace files produced. If libraries like the STL or most of Boost libraries are used, it is likely that most of the traces produced relate to those libraries and not to your own. Therefore, it is recommended to use `-isystem` when specifying the include directories for those libraries and then use the `-ignore-system` templight-option when producing the traces.
146 |
147 | *Warning*: Trace files produced by the profiler can be very large, especially in template-heavy code. So, use this tool with caution. It is not recommended to blindly generate templight trace files for all the source files of a particular project (e.g., using templight profiler in place of clang in a CMake build tree). You should first identify specific parts of your project that you suspect (or know) lead to template instantiation problems (e.g., compile-time performance issues, or actual bugs or failures), and then create a small source file that exercises those specific parts and produce a templight trace for that source file.
148 |
149 | ### Default Output Location
150 |
151 | The location and names of the output files for the templight traces needs some explanation, because it might not always be straight-forward. The main problem here is that templight is meant to be used as a drop-in replacement for the compiler (and it actually compiles the code, exactly as the vanilla Clang compiler does it). The problem is that you can invoke a compiler in many different ways. On typical small tests, you would simply invoke the compiler on a single source file and produce either an executable or an object file. In other case, you might invoke it with a list of source files to produce either an executable or a library. And for "real" projects, a build system will generally invoke the compiler for each source file, producing an object file each time, and later invoking the linker separately.
152 |
153 | Templight must find a reasonable place to output its traces in all those cases, and often, specifying an output location with `-output` does not really solve the problem (like this problem: multiple source files, one output location?). The only really straight-forward case is with the `-stdout` option, where the traces are simply printed out to the standard output (presumably to be piped elsewhere).
154 |
155 | **One Source File, One Object File** (without `-output` option): Whenever doing a simple compilation where each source file is turned into a single object file (i.e., when using the `-c` option), then the templight tracer will, by default, *output the traces into files located where the output object files are put* and with the same name, but with the addition of the templight extensions. In other words, for compilation instructions like `-c some/path/first_source.cpp some/other/path/second_source.cpp`, you would get traces files: `some/path/first_source.o.trace.pbf` and `some/other/path/second_source.o.trace.pbf`. Whichever options you specify to change the location or name of the generated object file, templight traces will follow. In other words, the default trace filenames are derived from the final output object-file names.
156 |
157 | **One Source File, One Object File** (with `-output` option): Because the `-output` option cannot deal with multiple files specified, templight will ignore this option in this case.
158 |
159 | **One Source File, (Some Output) File**: If you do any other operation that is like a simple compilation (no linking), such as using the `-S` option to general assembly listings or using the `-ast-dump` option, then the situation is analoguous to when you use the `-c` option (produce object-files). The templight trace file names are simply derived from whatever is the final output file name (e.g., `some_source.s.trace.pbf`). If you invoke templight in a way that does not involve any kind of an output file (such as syntax-only or ast-dump to stdout), then templight falls back to deriving the trace file names from the source file names (e.g., `some_source.cpp.trace.pbf`).
160 |
161 | The overall behavior in the above three cases is designed such that when templight is invoked as part of a compilation driven by a build-system (e.g., cmake, make, etc.), which is often done out-of-source, it will output all its traces wherever the build-system stashes the object-files, which is a safe and clean place to put them (e.g., avoid pollution in source tree, avoid possible file-permission problems (read-only source tree), etc..). It is also easy, through most build-systems to create scripts that will move or copy those traces out of those locations (that might be temporary under some setups) and put them wherever is more convenient.
162 |
163 | **Many Source Files, (Some Output) File**: If you invoke the compilation of several source files to be linked into a single executable or library, then templight will merge all the traces into a single output file, whose name is derived from the executable or library name. If no output name is specified, the compiler puts the executable into `a.out`, and templight will put its traces into `a.trace.pbf`. If you specify an output file via the `-output` option, then the trace will be put into that file.
164 |
165 | ## Using the Templight Debugger
166 |
167 | The templight debugger is invoked by specifying the templight-option `-debugger`. When the debugger is launched, it will interrupt the compilation with a console command prompt, just like GDB. The templight debugger is designed to work in a similar fashion as GDB, with many of the same familiar commands and behavior.
168 |
169 | Here is a quick reference for the available commands:
170 |
171 | `break ` |
172 | `b ` |
173 | `rbreak ` |
174 | `rb `:
175 | This command can be used to create a break-point at the instantiation (or any related actions, such as argument deductions) of the given template class or function, or any regular expression that matches with the instantiations that occur. If the base name of the template is used, like `my_class`, then the compilation will be interrupted at any instantiation in which that base name appears. If an specialization for the template is used, like `my_class`, then the compilation will be interrupted only when this specialization is encountered or instantiated.
176 |
177 | `delete ` |
178 | `d `:
179 | This command can be used to delete a break-point that was previously created with the `break` command. Each break-point is assigned an index number upon creation, and this index number should be used to remove that break-point. Use the `info break` (or `i b`) command to print the list of existing break-points so that the break-point index number can be retrieved, if forgotten.
180 |
181 | `run` | `r` |
182 | `continue` | `c`
183 | This command (in either forms or their short-hands) will resume compilation until the next break-point is encountered.
184 |
185 | `kill` | `k` |
186 | `quit` | `q`:
187 | This command (in either forms or their short-hands) will resume compilation until the end, ignoring all break-points. In other words, this means "finish the compilation without debugging".
188 |
189 | `step` | `s`:
190 | This command will step into the template instantiation, meaning that it will resume compilation until the next nested (or dependent) template is instantiated. For example, when instantiating a function template definition, function templates or class templates used inside the body of that function will be instantiated as part of it, and the `step` command allows you to step into those nested instantiations.
191 |
192 | `next` | `n`:
193 | This command will skip to the end of the current template instantiation, and thus, skipping all nested template instantiations. The debugger will interrupt only when leaving the current instantiation context, or if a break-point is encountered within the nested template instantiations.
194 |
195 | `where` | `backtrace` | `bt`:
196 | This command can be used to print the current stack of nested template instantiations.
197 |
198 | `info ` | `i `:
199 | This command can be used to query information about the state of the debugging session. The `` specifies one of the following options:
200 | - `frame` | `f`: Prints the information about the current template instantiation that the debugger is currently interrupted at.
201 | - `break` | `b`: Prints the list of all existing break-points.
202 | - `stack` | `s`: This is equivalent to calling `where` | `backtrace` | `bt` directly.
203 |
204 | `lookup ` |
205 | `l ` |
206 | `rlookup ` |
207 | `rl `:
208 | This command can be used to perform a look-up operation for a given identifier or regular expression, within the context of the current template instantiation. This will print out the match(es) that the compiler would make to the given identifier. For example, if you are in the instantiation of a member function of an STL container and lookup an identifier like `value_type`, it will point you to the location of that the declaration that the compiler will associate to that identifier in that context (presumably a nested typedef in the STL container class template).
209 |
210 | `typeof ` |
211 | `t ` |
212 | `rtypeof ` |
213 | `rt `:
214 | This command is similar to `lookup` except that instead of showing you the location of the matching identifier or regular expression (e.g., showing you a nested typedef or a data member) it will show you its type. If the identifier matches a variable, data member, function, or compile-time constant value, this command will show you the type of that object. If the identifier matches a type, it will show you what the actual type (fully instantiated) is. For example, if it matches a typedef or an alias, then the underlying type that it aliases will be shown (e.g., say you are inside the instantiation of the `std::vector::insert` function and issue `typeof value_type`, it should show you `double` as a result).
215 |
216 | `eval ` |
217 | `e ` |
218 | `reval ` |
219 | `re `:
220 | This command can be used to perform a look-up and evaluation operation for a given identifier or regular expression, within the context of the current template instantiation. This will print out the compile-time value(s) of the match(es) that the compiler would make to the given identifier. For example, if you are in the instantiation of a member function of an `numeric_limits` and lookup an identifier like `digits`, it will give you the compile-time value of that member.
221 |
222 | `whois ` |
223 | `w ` |
224 | `rwhois ` |
225 | `rw `:
226 | This command can be used to perform the equivalent of `lookup`, `eval` and `typeof` operations all at once for a given identifier or regular expression, within the context of the current template instantiation. This will print out the match(es) that the compiler would make to the given identifier and the message will contain the identifier that the look-up resolves to, its value (if any) and its canonical type, and will point to the location of the *identifier*. This command is mostly provided as a convenient all-in-one option for manual debugging using this debugger, and thus, provides more "human-readable" messages for various situations. The output of the other three fundamental commands (lookup, eval and typeof) are structured for providing all information in a way that is easy to parse by, for example, a graphical front-end for the debugger.
227 |
228 | `setmode verbose` |
229 | `setmode quiet`:
230 | This command can be used to toggle the verbose or quiet modes for the print outs. For example, in quiet mode (default), the location of declarations printed out during lookup or typeof operations will only name the source file and give the line / column numbers, but under verbose mode, it will also print out the corresponding line of source code and an indicator of the point (column) of the declaration (similar to diagnostic message of the compiler).
231 |
232 | *Warning*: The templight debugger is still in an *experimental* phase. You should expect that some of the behaviors mentioned in the above descriptions of the commands will not work as advertized, yet. If you observe any unusual or buggy behaviors, please notify the maintainer and provide an example source file with the sequence of commands that led to the observed behavior.
233 |
234 | ## Using Blacklists
235 |
236 | A blacklist file can be passed to templight (profiler or debugger) to filter entries such that they do not appear in the trace files or do not get involved in the step-through debugging. The blacklist files are simple text files where each line contains either `context ` or `identifier ` where `` is some regular expression statement that is used to match to the entries. Comments in the blacklist files are preceeded with a `#` character.
237 |
238 | The "context" regular expressions will be matched against declaration contexts of the entry being tested. For example, with `context std`, all elements of the std namespace will be filtered out (but note that some elements of std might refer to elements in other implementation-specific namespaces, such as `__gnu_cxx` for libstdc++ from GNU / GCC). Context blacklist elements can also be used to filter out nested instantiations. For example, using `context std::basic_string` would filter out the instantiation of the member functions and the nested templates of the `std::basic_string` class template, but not the instantiation of the class itself. In other words, declaration contexts are not only namespaces, but could also be classes (for members) and functions (for local declarations).
239 |
240 | The "identifier" regular expressions will be matched against the fully-scoped entry names themselves. For example, using `identifier std::basic_string` would filter out any instantiation of the `std::basic_string` class template.
241 |
242 | *Warning*: Beware of lexical clashes, because the regular expressions could blacklist things that you don't expect. For instance, using `context std` would filter out things in a `lastday` namespace too! It is therefore recommended to make the regular expressions as narrow as possible and use them wisely. For example, we could solve the example problem with `context ^std(::|$)` (match only context names starting with "std" and either ending there or being followed immediately by "::"). Also, an often practical and safer alternative to blacklists is to use the `-ignore-system` option, which ignores all entries coming out of a system-include header (standard headers and anything in directories specified with `-isystem` compiler option), which is not as fine-grained but is often more effective against complex libraries (e.g., STL, Boost, etc.) which can cause a lot of "noise" in the traces.
243 |
244 | Note that a pretty well-established convention for template-heavy code is to place implementation details into either `detail` namespace or in an anonymous namespace. Boost library implementers are particularly good with this. Therefore, it can be a good idea to filter out those things if you are not interested in seeing instantiations of such implementation details.
245 |
246 | Here is an example blacklist file that uses some of the examples mentioned above:
247 | ```bash
248 | # Filter out anything coming from the std namespace:
249 | context ^std(::|$)
250 |
251 | # Filter out things from libstdc++'s internal namespace:
252 | context __gnu_cxx
253 |
254 | # Filter out anonymous entries (unnamed namespaces or types):
255 | identifier anonymous
256 |
257 | # Filter out boost::something::or::nothing::detail namespace elements:
258 | context ^boost::.*detail
259 | ```
260 |
261 | ## Inspecting the profiles
262 |
263 | To begin to inspect the profiles, the starting point is probably to head over to the sister repository called [templight-tools](https://github.com/mikael-s-persson/templight-tools). There, you will find utilities to deal with the trace files produced by templight. In particular, you can use `templight-convert` to produce alternative formats, such as graphviz and callgrind, such that traces can be visualized. It is particularly recommended that you try out the "callgrind" output format, as it will allow the traces to be loaded in KCacheGrind for visualization.
264 |
265 | Any contribution or work towards applications to help inspect, analyse or visualize the profiles is more than welcomed!
266 |
267 | The [Templar application](https://github.com/schulmar/Templar) is one application that allows the user to open and inspect the traces produced by Templight.
268 |
269 | The [Metashell](https://github.com/sabel83/metashell) project is another application that provides inspection facilities for templight trace files. It is a whole different application altogether (not strictly just a trace inspector), but invokes templight under the hood to generate the template instantiation tree that it allows you to walk, along with the AST.
270 |
271 | ## Credits
272 |
273 | The original version of Templight was created by Zoltán Borók-Nagy, Zoltán Porkoláb and József Mihalicza:
274 | http://plc.inf.elte.hu/templight/
275 |
--------------------------------------------------------------------------------
/include/PrintableTemplightEntries.h:
--------------------------------------------------------------------------------
1 | //===- PrintableTemplightEntries.h -------------------*- C++ -*------------===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #ifndef LLVM_CLANG_PRINTABLE_TEMPLIGHT_ENTRIES_H
11 | #define LLVM_CLANG_PRINTABLE_TEMPLIGHT_ENTRIES_H
12 |
13 | #include
14 | #include
15 |
16 | namespace llvm {
17 | class raw_ostream;
18 | }
19 |
20 | namespace clang {
21 |
22 | struct PrintableTemplightEntryBegin {
23 | int SynthesisKind;
24 | std::string Name;
25 | std::string FileName;
26 | int Line;
27 | int Column;
28 | double TimeStamp;
29 | std::uint64_t MemoryUsage;
30 | std::string TempOri_FileName;
31 | int TempOri_Line;
32 | int TempOri_Column;
33 | };
34 |
35 | struct PrintableTemplightEntryEnd {
36 | double TimeStamp;
37 | std::uint64_t MemoryUsage;
38 | };
39 |
40 | class TemplightWriter {
41 | public:
42 | TemplightWriter(llvm::raw_ostream &aOS) : OutputOS(aOS){};
43 | virtual ~TemplightWriter(){};
44 |
45 | virtual void initialize(const std::string &aSourceName = "") = 0;
46 | virtual void finalize() = 0;
47 |
48 | virtual void printEntry(const PrintableTemplightEntryBegin &aEntry) = 0;
49 | virtual void printEntry(const PrintableTemplightEntryEnd &aEntry) = 0;
50 |
51 | protected:
52 | llvm::raw_ostream &OutputOS;
53 | };
54 |
55 | } // namespace clang
56 |
57 | #endif
58 |
--------------------------------------------------------------------------------
/include/TemplightAction.h:
--------------------------------------------------------------------------------
1 | //===- TemplightAction.h ------ Clang Templight Frontend Action -*- C++ -*-===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #ifndef LLVM_CLANG_TEMPLIGHT_TEMPLIGHT_ACTION_H
11 | #define LLVM_CLANG_TEMPLIGHT_TEMPLIGHT_ACTION_H
12 |
13 | #include
14 |
15 | #include "clang/Frontend/CompilerInstance.h"
16 | #include "clang/Frontend/FrontendAction.h"
17 | #include "llvm/ADT/StringRef.h"
18 |
19 | namespace clang {
20 |
21 | class TemplightAction : public WrapperFrontendAction {
22 | protected:
23 | std::unique_ptr
24 | CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override;
25 | bool BeginInvocation(CompilerInstance &CI) override;
26 | bool BeginSourceFileAction(CompilerInstance &CI) override;
27 | void ExecuteAction() override;
28 | void EndSourceFileAction() override;
29 |
30 | public:
31 | /// Construct a TemplightAction from an existing action, taking
32 | /// ownership of it.
33 | TemplightAction(std::unique_ptr WrappedAction);
34 |
35 | bool usesPreprocessorOnly() const override;
36 | TranslationUnitKind getTranslationUnitKind() override;
37 | bool hasPCHSupport() const override;
38 | bool hasASTFileSupport() const override;
39 | bool hasIRSupport() const override;
40 | bool hasCodeCompletionSupport() const override;
41 |
42 | static std::string CreateOutputFilename(CompilerInstance *CI,
43 | const std::string &OptOutputName,
44 | bool OptInstProfiler,
45 | bool OptOutputToStdOut,
46 | bool OptMemoryProfile);
47 |
48 | unsigned InstProfiler : 1;
49 | unsigned OutputToStdOut : 1;
50 | unsigned MemoryProfile : 1;
51 | unsigned OutputInSafeMode : 1;
52 | unsigned IgnoreSystemInst : 1;
53 | unsigned InteractiveDebug : 1;
54 | std::string OutputFilename;
55 | std::string BlackListFilename;
56 |
57 | private:
58 | void EnsureHasSema(CompilerInstance &CI);
59 | };
60 |
61 | } // namespace clang
62 |
63 | #endif
64 |
--------------------------------------------------------------------------------
/include/TemplightDebugger.h:
--------------------------------------------------------------------------------
1 | //===- TemplightDebugger.h ------ Clang Templight Debugger -*- C++ -*------===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #ifndef LLVM_CLANG_TEMPLIGHT_DEBUGGER_H
11 | #define LLVM_CLANG_TEMPLIGHT_DEBUGGER_H
12 |
13 | #include "clang/Sema/TemplateInstCallback.h"
14 |
15 | #include
16 | #include
17 |
18 | namespace clang {
19 |
20 | class TemplightDebugger : public TemplateInstantiationCallback {
21 | public:
22 | class InteractiveAgent; // forward-decl.
23 |
24 | void initialize(const Sema &TheSema) override;
25 | void finalize(const Sema &TheSema) override;
26 | void atTemplateBegin(const Sema &TheSema,
27 | const Sema::CodeSynthesisContext &Inst) override;
28 | void atTemplateEnd(const Sema &TheSema,
29 | const Sema::CodeSynthesisContext &Inst) override;
30 |
31 | private:
32 | unsigned MemoryFlag : 1;
33 | unsigned IgnoreSystemFlag : 1;
34 |
35 | std::unique_ptr Interactor;
36 |
37 | public:
38 | /// \brief Construct the templight debugger.
39 | TemplightDebugger(const Sema &TheSema, bool Memory = false,
40 | bool IgnoreSystem = false);
41 |
42 | ~TemplightDebugger() override;
43 |
44 | bool getMemoryFlag() const { return MemoryFlag; };
45 |
46 | void readBlacklists(const std::string &BLFilename);
47 | };
48 |
49 | } // namespace clang
50 |
51 | #endif
52 |
--------------------------------------------------------------------------------
/include/TemplightEntryPrinter.h:
--------------------------------------------------------------------------------
1 | //===- TemplightProtobufReader.h --------------------------*- C++ -*-------===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #ifndef LLVM_CLANG_TEMPLIGHT_ENTRY_PRINTER_H
11 | #define LLVM_CLANG_TEMPLIGHT_ENTRY_PRINTER_H
12 |
13 | #include "PrintableTemplightEntries.h"
14 |
15 | #include
16 | #include
17 |
18 | namespace llvm {
19 | class Regex;
20 | }
21 |
22 | namespace clang {
23 |
24 | class TemplightWriter;
25 |
26 | class TemplightEntryPrinter {
27 | public:
28 | void skipEntry();
29 | bool shouldIgnoreEntry(const PrintableTemplightEntryBegin &Entry);
30 | bool shouldIgnoreEntry(const PrintableTemplightEntryEnd &Entry);
31 |
32 | void printEntry(const PrintableTemplightEntryBegin &Entry);
33 | void printEntry(const PrintableTemplightEntryEnd &Entry);
34 |
35 | void initialize(const std::string &SourceName = "");
36 | void finalize();
37 |
38 | TemplightEntryPrinter(const std::string &Output);
39 | ~TemplightEntryPrinter();
40 |
41 | bool isValid() const;
42 |
43 | llvm::raw_ostream *getTraceStream() const;
44 | void takeWriter(TemplightWriter *aPWriter);
45 |
46 | void readBlacklists(const std::string &BLFilename);
47 |
48 | private:
49 | std::size_t SkippedEndingsCount;
50 | std::unique_ptr CoRegex;
51 | std::unique_ptr IdRegex;
52 |
53 | llvm::raw_ostream *TraceOS;
54 |
55 | std::unique_ptr p_writer;
56 | };
57 |
58 | } // namespace clang
59 |
60 | #endif
61 |
--------------------------------------------------------------------------------
/include/TemplightProtobufWriter.h:
--------------------------------------------------------------------------------
1 | //===- TemplightProtobufWriter.h --------------------*- C++ -*-------------===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #ifndef LLVM_CLANG_TEMPLIGHT_PROTOBUF_WRITER_H
11 | #define LLVM_CLANG_TEMPLIGHT_PROTOBUF_WRITER_H
12 |
13 | #include "PrintableTemplightEntries.h"
14 |
15 | #include
16 | #include
17 |
18 | namespace llvm {
19 | class raw_ostream;
20 | }
21 |
22 | namespace clang {
23 |
24 | class TemplightProtobufWriter : public TemplightWriter {
25 | private:
26 | std::string buffer;
27 | std::unordered_map fileNameMap;
28 | std::unordered_map templateNameMap;
29 | int compressionMode;
30 |
31 | std::size_t createDictionaryEntry(const std::string &Name);
32 | std::string printEntryLocation(const std::string &FileName, int Line,
33 | int Column);
34 | std::string printTemplateName(const std::string &Name);
35 |
36 | public:
37 | TemplightProtobufWriter(llvm::raw_ostream &aOS, int aCompressLevel = 2);
38 |
39 | void initialize(const std::string &aSourceName = "") override;
40 | void finalize() override;
41 |
42 | void printEntry(const PrintableTemplightEntryBegin &aEntry) override;
43 | void printEntry(const PrintableTemplightEntryEnd &aEntry) override;
44 | };
45 |
46 | } // namespace clang
47 |
48 | #endif
49 |
--------------------------------------------------------------------------------
/include/TemplightTracer.h:
--------------------------------------------------------------------------------
1 | //===- TemplightTracer.h ---------------------------*- C++ -*--------------===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #ifndef LLVM_CLANG_TEMPLIGHT_TRACER_H
11 | #define LLVM_CLANG_TEMPLIGHT_TRACER_H
12 |
13 | #include "clang/Sema/TemplateInstCallback.h"
14 |
15 | #include
16 | #include
17 |
18 | namespace clang {
19 |
20 | class TemplightTracer : public TemplateInstantiationCallback {
21 | public:
22 | class TracePrinter; // forward-decl.
23 |
24 | void initialize(const Sema &TheSema) override;
25 | void finalize(const Sema &TheSema) override;
26 | void atTemplateBegin(const Sema &TheSema,
27 | const Sema::CodeSynthesisContext &Inst) override;
28 | void atTemplateEnd(const Sema &TheSema,
29 | const Sema::CodeSynthesisContext &Inst) override;
30 |
31 | private:
32 | unsigned MemoryFlag : 1;
33 | unsigned SafeModeFlag : 1;
34 |
35 | std::unique_ptr Printer;
36 |
37 | public:
38 | /// \brief Sets the format type of the template trace file.
39 | /// The argument can be xml/yaml/text
40 | TemplightTracer(const Sema &TheSema, std::string Output = "",
41 | bool Memory = false, bool Safemode = false,
42 | bool IgnoreSystem = false);
43 |
44 | ~TemplightTracer() override;
45 |
46 | bool getMemoryFlag() const { return MemoryFlag; };
47 | bool getSafeModeFlag() const { return SafeModeFlag; };
48 |
49 | void readBlacklists(const std::string &BLFilename);
50 | };
51 |
52 | } // namespace clang
53 |
54 | #endif
55 |
--------------------------------------------------------------------------------
/include/ThinProtobuf.h:
--------------------------------------------------------------------------------
1 | //===- TemplightProtobufWriter.cpp -----------------------*- C++ -*--------===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #ifndef LLVM_SUPPORT_THIN_PROTOBUF_H
11 | #define LLVM_SUPPORT_THIN_PROTOBUF_H
12 |
13 | #include
14 | #include
15 | #include
16 |
17 | #include
18 | #include
19 |
20 | namespace llvm {
21 |
22 | namespace protobuf {
23 |
24 | namespace {
25 |
26 | union float_to_ulong {
27 | float f;
28 | std::uint32_t ui32;
29 | };
30 |
31 | union double_to_ulong {
32 | double d;
33 | std::uint64_t ui64;
34 | std::uint32_t ui32[2];
35 | };
36 |
37 | union int64_to_uint64 {
38 | std::int64_t i64;
39 | std::uint64_t ui64;
40 | };
41 |
42 | } // namespace
43 |
44 | inline std::uint64_t loadVarInt(StringRef &p_buf) {
45 | std::uint64_t u = 0;
46 | if (p_buf.empty())
47 | return u;
48 | std::uint8_t shifts = 0;
49 | while (p_buf.front() & 0x80) {
50 | u |= (p_buf.front() & 0x7F) << shifts;
51 | p_buf = p_buf.drop_front(1);
52 | if (p_buf.empty())
53 | return u;
54 | shifts += 7;
55 | };
56 | u |= (p_buf.front() & 0x7F) << shifts;
57 | p_buf = p_buf.drop_front(1);
58 | return u;
59 | }
60 |
61 | template struct getVarIntWire {
62 | static const unsigned int value = (tag << 3);
63 | };
64 |
65 | template struct getIntWire {
66 | static const unsigned int value = (tag << 3);
67 | };
68 |
69 | inline std::int64_t loadSInt(StringRef &p_buf) {
70 | std::uint64_t u = loadVarInt(p_buf);
71 | return (u >> 1) ^ (-static_cast(u & 1));
72 | }
73 |
74 | template struct getSIntWire {
75 | static const unsigned int value = (tag << 3);
76 | };
77 |
78 | inline double loadDouble(StringRef &p_buf) {
79 | if (p_buf.size() < sizeof(double_to_ulong)) {
80 | p_buf = p_buf.drop_front(p_buf.size());
81 | return double(0.0);
82 | };
83 | double_to_ulong tmp;
84 | std::memcpy(reinterpret_cast(&tmp), p_buf.data(),
85 | sizeof(double_to_ulong));
86 | p_buf = p_buf.drop_front(sizeof(double_to_ulong));
87 | tmp.ui64 = llvm::support::endian::byte_swap<
88 | std::uint64_t, llvm::endianness::little>(tmp.ui64);
89 | return tmp.d;
90 | }
91 |
92 | template struct getDoubleWire {
93 | static const unsigned int value = (tag << 3) | 1;
94 | };
95 |
96 | inline float loadFloat(StringRef &p_buf) {
97 | if (p_buf.size() < sizeof(float_to_ulong)) {
98 | p_buf = p_buf.drop_front(p_buf.size());
99 | return float(0.0);
100 | };
101 | float_to_ulong tmp;
102 | std::memcpy(reinterpret_cast(&tmp), p_buf.data(),
103 | sizeof(float_to_ulong));
104 | p_buf = p_buf.drop_front(sizeof(float_to_ulong));
105 | tmp.ui32 = llvm::support::endian::byte_swap<
106 | std::uint32_t, llvm::endianness::little>(tmp.ui32);
107 | return tmp.f;
108 | }
109 |
110 | template struct getFloatWire {
111 | static const unsigned int value = (tag << 3) | 5;
112 | };
113 |
114 | inline bool loadBool(StringRef &p_buf) {
115 | if (p_buf.empty())
116 | return false;
117 | char tmp = p_buf.front();
118 | p_buf = p_buf.drop_front(1);
119 | return tmp;
120 | }
121 |
122 | template struct getBoolWire {
123 | static const unsigned int value = (tag << 3);
124 | };
125 |
126 | inline std::string loadString(StringRef &p_buf) {
127 | unsigned int u = loadVarInt(p_buf);
128 | if (p_buf.size() < u) {
129 | p_buf = p_buf.drop_front(p_buf.size());
130 | return std::string();
131 | };
132 | std::string s(p_buf.data(), u);
133 | p_buf = p_buf.drop_front(u);
134 | return s; // NRVO
135 | }
136 |
137 | template struct getStringWire {
138 | static const unsigned int value = (tag << 3) | 2;
139 | };
140 |
141 | inline void skipData(StringRef &p_buf, unsigned int wire) {
142 | switch (wire & 0x7) {
143 | case 0:
144 | loadVarInt(p_buf);
145 | break;
146 | case 1:
147 | if (p_buf.size() < sizeof(double_to_ulong))
148 | p_buf = p_buf.drop_front(p_buf.size());
149 | else
150 | p_buf = p_buf.drop_front(sizeof(double_to_ulong));
151 | break;
152 | case 2: {
153 | unsigned int u = loadVarInt(p_buf);
154 | if (p_buf.size() < u)
155 | p_buf = p_buf.drop_front(p_buf.size());
156 | else
157 | p_buf = p_buf.drop_front(u);
158 | break;
159 | };
160 | case 5:
161 | if (p_buf.size() < sizeof(float_to_ulong))
162 | p_buf = p_buf.drop_front(p_buf.size());
163 | else
164 | p_buf = p_buf.drop_front(sizeof(float_to_ulong));
165 | break;
166 | default:
167 | break;
168 | }
169 | }
170 |
171 | inline void saveVarInt(llvm::raw_ostream &OS, std::uint64_t u) {
172 | std::uint8_t buf[] = {
173 | 0, 0, 0, 0, 0,
174 | 0, 0, 0, 0, 0}; // 80-bits, supports at most a 64-bit varint.
175 | std::uint8_t *pbuf = buf;
176 | *pbuf = (u & 0x7F);
177 | u >>= 7;
178 | while (u) {
179 | *pbuf |= 0x80; // set first msb because there is more to come.
180 | pbuf++;
181 | *pbuf = (u & 0x7F);
182 | u >>= 7;
183 | };
184 | OS.write(reinterpret_cast(buf), pbuf - buf + 1);
185 | }
186 |
187 | inline void saveVarInt(llvm::raw_ostream &OS, unsigned int tag,
188 | std::uint64_t u) {
189 | saveVarInt(OS, (tag << 3)); // wire-type 0: Varint.
190 | saveVarInt(OS, u);
191 | }
192 |
193 | inline void saveInt(llvm::raw_ostream &OS, unsigned int tag, std::int64_t i) {
194 | saveVarInt(OS, (tag << 3)); // wire-type 0: Varint.
195 | int64_to_uint64 tmp;
196 | tmp.i64 = i;
197 | saveVarInt(OS, tmp.ui64);
198 | }
199 |
200 | inline void saveSInt(llvm::raw_ostream &OS, std::int64_t i) {
201 | // Apply the ZigZag encoding for the sign:
202 | saveVarInt(OS, (i << 1) ^ (i >> (sizeof(std::int64_t) * 8 - 1)));
203 | }
204 |
205 | inline void saveSInt(llvm::raw_ostream &OS, unsigned int tag, std::int64_t i) {
206 | saveVarInt(OS, (tag << 3)); // wire-type 0: Varint.
207 | saveSInt(OS, i);
208 | }
209 |
210 | inline void saveDouble(llvm::raw_ostream &OS, double d) {
211 | double_to_ulong tmp = {d};
212 | tmp.ui64 = llvm::support::endian::byte_swap<
213 | std::uint64_t, llvm::endianness::little>(tmp.ui64);
214 | OS.write(reinterpret_cast(&tmp), sizeof(double_to_ulong));
215 | }
216 |
217 | inline void saveDouble(llvm::raw_ostream &OS, unsigned int tag, double d) {
218 | saveVarInt(OS, (tag << 3) | 1); // wire-type 1: 64-bit.
219 | saveDouble(OS, d);
220 | }
221 |
222 | inline void saveFloat(llvm::raw_ostream &OS, float d) {
223 | float_to_ulong tmp = {d};
224 | tmp.ui32 = llvm::support::endian::byte_swap<
225 | std::uint32_t, llvm::endianness::little>(tmp.ui32);
226 | OS.write(reinterpret_cast(&tmp), sizeof(float_to_ulong));
227 | }
228 |
229 | inline void saveFloat(llvm::raw_ostream &OS, unsigned int tag, float d) {
230 | saveVarInt(OS, (tag << 3) | 5); // wire-type 5: 32-bit.
231 | saveFloat(OS, d);
232 | }
233 |
234 | inline void saveBool(llvm::raw_ostream &OS, bool b) {
235 | char tmp = 0;
236 | if (b)
237 | tmp = 1;
238 | OS.write(&tmp, 1);
239 | }
240 |
241 | inline void saveBool(llvm::raw_ostream &OS, unsigned int tag, bool b) {
242 | saveVarInt(OS, (tag << 3)); // wire-type 0: varint.
243 | saveBool(OS, b);
244 | }
245 |
246 | inline void saveString(llvm::raw_ostream &OS, StringRef s) {
247 | unsigned int u = s.size();
248 | saveVarInt(OS, u);
249 | OS.write(s.data(), u);
250 | }
251 |
252 | inline void saveString(llvm::raw_ostream &OS, unsigned int tag, StringRef s) {
253 | saveVarInt(OS, (tag << 3) | 2); // wire-type 2: length-delimited.
254 | saveString(OS, s);
255 | }
256 |
257 | } // namespace protobuf
258 |
259 | } // namespace llvm
260 |
261 | #endif
262 |
--------------------------------------------------------------------------------
/lib/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_clang_library(clangTemplight
2 | TemplightAction.cpp
3 | TemplightDebugger.cpp
4 | TemplightEntryPrinter.cpp
5 | TemplightProtobufWriter.cpp
6 | TemplightTracer.cpp
7 |
8 | LINK_LIBS
9 | clangAST
10 | clangBasic
11 | clangFrontend
12 | clangLex
13 | clangSema
14 | clangSerialization
15 | )
16 |
--------------------------------------------------------------------------------
/lib/TemplightAction.cpp:
--------------------------------------------------------------------------------
1 | //===- TemplightAction.cpp --------------------------------*- C++-*--------===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #include "TemplightAction.h"
11 | #include "TemplightDebugger.h"
12 | #include "TemplightTracer.h"
13 |
14 | #include "clang/Basic/FileManager.h"
15 | #include
16 | #include
17 | #include
18 |
19 | #include
20 | #include
21 | #include
22 |
23 | #include
24 |
25 | namespace clang {
26 |
27 | std::unique_ptr
28 | TemplightAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
29 | return WrapperFrontendAction::CreateASTConsumer(CI, InFile);
30 | }
31 | bool TemplightAction::BeginInvocation(CompilerInstance &CI) {
32 | return WrapperFrontendAction::BeginInvocation(CI);
33 | }
34 | bool TemplightAction::BeginSourceFileAction(CompilerInstance &CI) {
35 | return WrapperFrontendAction::BeginSourceFileAction(CI);
36 | }
37 |
38 | std::string TemplightAction::CreateOutputFilename(
39 | CompilerInstance *CI, const std::string &OptOutputName,
40 | bool OptInstProfiler, bool OptOutputToStdOut, bool OptMemoryProfile) {
41 | std::string result;
42 |
43 | if (!OptInstProfiler) {
44 | return result; // no need for an output-filename.
45 | }
46 |
47 | if (OptOutputToStdOut) {
48 | return "-";
49 | }
50 | if (CI && OptOutputName.empty()) {
51 | result = CI->getFrontendOpts().OutputFile;
52 | } else {
53 | result = OptOutputName;
54 | }
55 |
56 | // Should never get executed.
57 | if (CI && result.empty()) {
58 | // then, derive output name from the input name:
59 | if (CI->hasSourceManager()) {
60 | FileID fileID = CI->getSourceManager().getMainFileID();
61 | OptionalFileEntryRef file_ref =
62 | CI->getSourceManager().getFileEntryRefForID(fileID);
63 | if (file_ref.has_value()) {
64 | result = file_ref->getName().str();
65 | } else {// or, last resort:
66 | result = "a";
67 | }
68 | } else { // or, last resort:
69 | result = "a";
70 | }
71 | }
72 |
73 | if (result.rfind(".trace.") == std::string::npos) {
74 | result += (OptMemoryProfile ? ".memory.trace." : ".trace.");
75 | result += "pbf";
76 | }
77 |
78 | return result;
79 | }
80 |
81 | void TemplightAction::EnsureHasSema(CompilerInstance &CI) {
82 | if (!CI.hasSema()) {
83 | // This part is normally done by ASTFrontEndAction, but needs to happen
84 | // before Templight observers can be created ----------------------->>
85 | // FIXME: Move the truncation aspect of this into Sema, we delayed this till
86 | // here so the source manager would be initialized.
87 | if (hasCodeCompletionSupport() &&
88 | !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
89 | CI.createCodeCompletionConsumer();
90 |
91 | // Use a code completion consumer?
92 | CodeCompleteConsumer *CompletionConsumer = nullptr;
93 | if (CI.hasCodeCompletionConsumer())
94 | CompletionConsumer = &CI.getCodeCompletionConsumer();
95 |
96 | CI.createSema(getTranslationUnitKind(), CompletionConsumer);
97 | //<<--------------------------------------------------------------
98 | }
99 | }
100 |
101 | void TemplightAction::ExecuteAction() {
102 |
103 | CompilerInstance &CI = WrapperFrontendAction::getCompilerInstance();
104 | if (!CI.hasPreprocessor())
105 | return;
106 |
107 | if (InstProfiler) {
108 | EnsureHasSema(CI);
109 |
110 | std::unique_ptr p_t(
111 | new TemplightTracer(CI.getSema(), OutputFilename, MemoryProfile,
112 | OutputInSafeMode, IgnoreSystemInst));
113 | p_t->readBlacklists(BlackListFilename);
114 | CI.getSema().TemplateInstCallbacks.push_back(std::move(p_t));
115 | }
116 | if (InteractiveDebug) {
117 | EnsureHasSema(CI);
118 |
119 | std::unique_ptr p_t(
120 | new TemplightDebugger(CI.getSema(), MemoryProfile, IgnoreSystemInst));
121 | p_t->readBlacklists(BlackListFilename);
122 | CI.getSema().TemplateInstCallbacks.push_back(std::move(p_t));
123 | }
124 |
125 | WrapperFrontendAction::ExecuteAction();
126 | }
127 | void TemplightAction::EndSourceFileAction() {
128 | WrapperFrontendAction::EndSourceFileAction();
129 | }
130 |
131 | bool TemplightAction::usesPreprocessorOnly() const {
132 | return WrapperFrontendAction::usesPreprocessorOnly();
133 | }
134 | TranslationUnitKind TemplightAction::getTranslationUnitKind() {
135 | return WrapperFrontendAction::getTranslationUnitKind();
136 | }
137 | bool TemplightAction::hasPCHSupport() const {
138 | return WrapperFrontendAction::hasPCHSupport();
139 | }
140 | bool TemplightAction::hasASTFileSupport() const {
141 | return WrapperFrontendAction::hasASTFileSupport();
142 | }
143 | bool TemplightAction::hasIRSupport() const {
144 | return WrapperFrontendAction::hasIRSupport();
145 | }
146 | bool TemplightAction::hasCodeCompletionSupport() const {
147 | return WrapperFrontendAction::hasCodeCompletionSupport();
148 | }
149 |
150 | TemplightAction::TemplightAction(std::unique_ptr WrappedAction)
151 | : WrapperFrontendAction(std::move(WrappedAction)), InstProfiler(false),
152 | OutputToStdOut(false), MemoryProfile(false), OutputInSafeMode(false),
153 | IgnoreSystemInst(false), InteractiveDebug(false) {}
154 |
155 | } // namespace clang
156 |
--------------------------------------------------------------------------------
/lib/TemplightEntryPrinter.cpp:
--------------------------------------------------------------------------------
1 | //===- TemplightEntryPrinter.cpp --------------------*- C++ -*-------------===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #include "TemplightEntryPrinter.h"
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | namespace clang {
18 |
19 | void TemplightEntryPrinter::skipEntry() {
20 | if (SkippedEndingsCount) {
21 | ++SkippedEndingsCount; // note: this is needed because skipped entries are
22 | // begin entries for which "shouldIgnoreEntry" is
23 | // never called.
24 | return; // Already skipping entries.
25 | }
26 | SkippedEndingsCount = 1;
27 | }
28 |
29 | bool TemplightEntryPrinter::shouldIgnoreEntry(
30 | const PrintableTemplightEntryBegin &Entry) {
31 | // Check the black-lists:
32 | // (1) Is currently ignoring entries?
33 | if (SkippedEndingsCount) {
34 | ++SkippedEndingsCount;
35 | return true;
36 | }
37 | // (2) Regexes:
38 | if ((CoRegex && (CoRegex->match(Entry.Name))) ||
39 | (IdRegex && (IdRegex->match(Entry.Name)))) {
40 | skipEntry();
41 | return true;
42 | }
43 |
44 | return false;
45 | }
46 |
47 | bool TemplightEntryPrinter::shouldIgnoreEntry(
48 | const PrintableTemplightEntryEnd &Entry) {
49 | // Check the black-lists:
50 | // (1) Is currently ignoring entries?
51 | if (SkippedEndingsCount) {
52 | --SkippedEndingsCount;
53 | return true;
54 | }
55 | return false;
56 | }
57 |
58 | void TemplightEntryPrinter::printEntry(
59 | const PrintableTemplightEntryBegin &Entry) {
60 | if (shouldIgnoreEntry(Entry))
61 | return;
62 |
63 | if (p_writer)
64 | p_writer->printEntry(Entry);
65 | }
66 |
67 | void TemplightEntryPrinter::printEntry(
68 | const PrintableTemplightEntryEnd &Entry) {
69 | if (shouldIgnoreEntry(Entry))
70 | return;
71 |
72 | if (p_writer)
73 | p_writer->printEntry(Entry);
74 | }
75 |
76 | void TemplightEntryPrinter::initialize(const std::string &SourceName) {
77 | if (p_writer)
78 | p_writer->initialize(SourceName);
79 | }
80 |
81 | void TemplightEntryPrinter::finalize() {
82 | if (p_writer)
83 | p_writer->finalize();
84 | }
85 |
86 | TemplightEntryPrinter::TemplightEntryPrinter(const std::string &Output)
87 | : SkippedEndingsCount(0), TraceOS(0) {
88 | if (Output == "-") {
89 | TraceOS = &llvm::outs();
90 | } else {
91 | std::error_code error;
92 | TraceOS = new llvm::raw_fd_ostream(Output, error, llvm::sys::fs::OF_None);
93 | if (error) {
94 | llvm::errs() << "Error: [Templight] Can not open file to write trace of "
95 | "template instantiations: "
96 | << Output << " Error: " << error.message();
97 | TraceOS = 0;
98 | return;
99 | }
100 | }
101 | }
102 |
103 | TemplightEntryPrinter::~TemplightEntryPrinter() {
104 | p_writer.reset(); // Delete writer before the trace-OS.
105 | if (TraceOS) {
106 | TraceOS->flush();
107 | if (TraceOS != &llvm::outs())
108 | delete TraceOS;
109 | }
110 | }
111 |
112 | bool TemplightEntryPrinter::isValid() const { return p_writer.get(); }
113 |
114 | llvm::raw_ostream *TemplightEntryPrinter::getTraceStream() const {
115 | return TraceOS;
116 | }
117 |
118 | void TemplightEntryPrinter::takeWriter(TemplightWriter *aPWriter) {
119 | p_writer.reset(aPWriter);
120 | }
121 |
122 | void TemplightEntryPrinter::readBlacklists(const std::string &BLFilename) {
123 | if (BLFilename.empty()) {
124 | CoRegex.reset();
125 | IdRegex.reset();
126 | return;
127 | }
128 |
129 | std::string CoPattern, IdPattern;
130 |
131 | llvm::ErrorOr> file_epbuf =
132 | llvm::MemoryBuffer::getFile(llvm::Twine(BLFilename));
133 | if (!file_epbuf || (!file_epbuf.get())) {
134 | llvm::errs()
135 | << "Error: [Templight-Action] Could not open the blacklist file!\n";
136 | CoRegex.reset();
137 | IdRegex.reset();
138 | return;
139 | }
140 |
141 | llvm::Regex findCo("^context ");
142 | llvm::Regex findId("^identifier ");
143 |
144 | const char *it = file_epbuf.get()->getBufferStart();
145 | const char *it_mark = file_epbuf.get()->getBufferStart();
146 | const char *it_end = file_epbuf.get()->getBufferEnd();
147 |
148 | while (it_mark != it_end) {
149 | it_mark = std::find(it, it_end, '\n');
150 | if (*(it_mark - 1) == '\r')
151 | --it_mark;
152 | llvm::StringRef curLine(&(*it), it_mark - it);
153 | if (findCo.match(curLine)) {
154 | if (!CoPattern.empty())
155 | CoPattern += '|';
156 | CoPattern += '(';
157 | CoPattern.append(&(*(it + 8)), it_mark - it - 8);
158 | CoPattern += ')';
159 | } else if (findId.match(curLine)) {
160 | if (!IdPattern.empty())
161 | IdPattern += '|';
162 | IdPattern += '(';
163 | IdPattern.append(&(*(it + 11)), it_mark - it - 11);
164 | IdPattern += ')';
165 | }
166 | while ((it_mark != it_end) && ((*it_mark == '\n') || (*it_mark == '\r')))
167 | ++it_mark;
168 | it = it_mark;
169 | }
170 |
171 | CoRegex.reset(new llvm::Regex(CoPattern));
172 | IdRegex.reset(new llvm::Regex(IdPattern));
173 | return;
174 | }
175 |
176 | } // namespace clang
177 |
--------------------------------------------------------------------------------
/lib/TemplightProtobufWriter.cpp:
--------------------------------------------------------------------------------
1 | //===- TemplightProtobufWriter.cpp ------------*- C++ -*-------------------===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #include "TemplightProtobufWriter.h"
11 | #include "PrintableTemplightEntries.h"
12 |
13 | #include "ThinProtobuf.h"
14 | #include "llvm/ADT/StringExtras.h"
15 |
16 | #include
17 | #include
18 | #include
19 |
20 | #include
21 | #include
22 |
23 | namespace clang {
24 |
25 | TemplightProtobufWriter::TemplightProtobufWriter(llvm::raw_ostream &aOS,
26 | int aCompressLevel)
27 | : TemplightWriter(aOS), compressionMode(aCompressLevel) {}
28 |
29 | void TemplightProtobufWriter::initialize(const std::string &aSourceName) {
30 |
31 | std::string hdr_contents;
32 | {
33 | llvm::raw_string_ostream OS_inner(hdr_contents);
34 |
35 | /*
36 | message TemplightHeader {
37 | required uint32 version = 1;
38 | optional string source_file = 2;
39 | }
40 | */
41 |
42 | llvm::protobuf::saveVarInt(OS_inner, 1, 1); // version
43 | if (!aSourceName.empty())
44 | llvm::protobuf::saveString(OS_inner, 2, aSourceName); // source_file
45 | }
46 |
47 | llvm::raw_string_ostream OS(buffer);
48 |
49 | // required TemplightHeader header = 1;
50 | llvm::protobuf::saveString(OS, 1, hdr_contents);
51 | }
52 |
53 | void TemplightProtobufWriter::finalize() {
54 | // repeated TemplightTrace traces = 1;
55 | llvm::protobuf::saveString(OutputOS, 1, buffer);
56 | }
57 |
58 | std::string
59 | TemplightProtobufWriter::printEntryLocation(const std::string &FileName,
60 | int Line, int Column) {
61 |
62 | /*
63 | message SourceLocation {
64 | optional string file_name = 1;
65 | required uint32 file_id = 2;
66 | required uint32 line = 3;
67 | optional uint32 column = 4;
68 | }
69 | */
70 |
71 | std::string location_contents;
72 | llvm::raw_string_ostream OS_inner(location_contents);
73 |
74 | std::unordered_map::iterator it =
75 | fileNameMap.find(FileName);
76 |
77 | if (it == fileNameMap.end()) {
78 | llvm::protobuf::saveString(OS_inner, 1, FileName); // file_name
79 | std::size_t file_id = fileNameMap.size();
80 | llvm::protobuf::saveVarInt(OS_inner, 2, file_id); // file_id
81 | fileNameMap[FileName] = file_id;
82 | } else {
83 | llvm::protobuf::saveVarInt(OS_inner, 2, it->second); // file_id
84 | }
85 |
86 | llvm::protobuf::saveVarInt(OS_inner, 3, Line); // line
87 | llvm::protobuf::saveVarInt(OS_inner, 4, Column); // column
88 |
89 | OS_inner.str();
90 |
91 | return location_contents; // NRVO
92 | }
93 |
94 | static void trimSpaces(std::string::iterator &it,
95 | std::string::iterator &it_end) {
96 | while (it < it_end) {
97 | if (*it == ' ')
98 | ++it;
99 | else if (*it_end == ' ')
100 | --it_end;
101 | else
102 | break;
103 | }
104 | ++it_end;
105 | }
106 |
107 | std::size_t
108 | TemplightProtobufWriter::createDictionaryEntry(const std::string &NameOrig) {
109 | std::unordered_map::iterator it_found =
110 | templateNameMap.find(NameOrig);
111 | if (it_found != templateNameMap.end())
112 | return it_found->second;
113 |
114 | // FIXME: Convert this code to being constructive of "Name", instead of
115 | // destructive (replacing sub-strings with '\0' characters).
116 | std::string Name = NameOrig;
117 | std::string::iterator it_open = Name.end();
118 | std::string::iterator it_colon_lo = Name.begin();
119 | int srch_state = 0;
120 | llvm::SmallVector markers;
121 | for (std::string::iterator it = Name.begin(); it != Name.end(); ++it) {
122 | switch (srch_state) {
123 | case 0:
124 | if (*it == '<') {
125 | // check for "operator<<", "operator<" and "operator<="
126 | llvm::StringRef test_str(Name.data(), it - Name.begin() + 1);
127 | if (test_str.ends_with("operator<")) {
128 | it_open = Name.end();
129 | srch_state = 0;
130 | } else {
131 | it_open = it;
132 | ++srch_state;
133 | }
134 | } else if ((*it == ':') && (it + 1 < Name.end()) && (*(it + 1) == ':')) {
135 | if (it_colon_lo < it) {
136 | markers.push_back(
137 | createDictionaryEntry(std::string(it_colon_lo, it)));
138 | std::size_t offset_lo = it_colon_lo - Name.begin();
139 | Name.replace(it_colon_lo, it, 1, '\0');
140 | it = Name.begin() + offset_lo + 2;
141 | } else {
142 | it += 1;
143 | }
144 | it_colon_lo = it + 1;
145 | it_open = Name.end();
146 | }
147 | break;
148 | case 1:
149 | if (*it == '<') {
150 | // check for "operator<<" and "operator<"
151 | llvm::StringRef test_str(Name.data(), it - Name.begin() + 1);
152 | if (test_str.ends_with("operator<<<")) {
153 | it_open = it;
154 | srch_state = 1;
155 | } else {
156 | ++srch_state;
157 | }
158 | } else if ((*it == ',') || (*it == '>')) {
159 | if (it_colon_lo < it_open) {
160 | std::size_t offset_end = it - it_open;
161 | std::size_t offset_lo = it_colon_lo - Name.begin();
162 | markers.push_back(
163 | createDictionaryEntry(std::string(it_colon_lo, it_open)));
164 | Name.replace(it_colon_lo, it_open, 1, '\0');
165 | it_open = Name.begin() + offset_lo + 1;
166 | it = it_open + offset_end;
167 | it_colon_lo = Name.end();
168 | }
169 | std::string::iterator it_lo = it_open + 1;
170 | std::string::iterator it_hi = it - 1;
171 | trimSpaces(it_lo, it_hi);
172 | // Create or find the marker entry:
173 | markers.push_back(createDictionaryEntry(std::string(it_lo, it_hi)));
174 | std::size_t offset_end = it - it_hi;
175 | std::size_t offset_lo = it_lo - Name.begin();
176 | Name.replace(it_lo, it_hi, 1, '\0');
177 | it = Name.begin() + offset_lo + 1 + offset_end;
178 | it_open = it;
179 | it_colon_lo = Name.end();
180 | if (*it == '>') {
181 | it_open = Name.end();
182 | srch_state = 0;
183 | it_colon_lo = it + 1;
184 | }
185 | }
186 | break;
187 | default:
188 | if (*it == '<') {
189 | ++srch_state;
190 | } else if (*it == '>') {
191 | --srch_state;
192 | }
193 | break;
194 | }
195 | }
196 | if (!markers.empty() && it_colon_lo != Name.end()) {
197 | markers.push_back(
198 | createDictionaryEntry(std::string(it_colon_lo, Name.end())));
199 | Name.replace(it_colon_lo, Name.end(), 1, '\0');
200 | }
201 |
202 | /*
203 | message DictionaryEntry {
204 | required string marked_name = 1;
205 | repeated uint32 marker_ids = 2;
206 | }
207 | */
208 | std::string dict_entry;
209 | llvm::raw_string_ostream OS_dict(dict_entry);
210 | llvm::protobuf::saveString(OS_dict, 1, Name); // marked_name
211 | for (llvm::SmallVector::iterator mk = markers.begin(),
212 | mk_end = markers.end();
213 | mk != mk_end; ++mk) {
214 | llvm::protobuf::saveVarInt(OS_dict, 2, *mk); // marker_ids
215 | }
216 | OS_dict.str();
217 |
218 | std::size_t id = templateNameMap.size();
219 | templateNameMap[NameOrig] = id;
220 |
221 | llvm::raw_string_ostream OS_outer(buffer);
222 | // repeated DictionaryEntry names = 3;
223 | llvm::protobuf::saveString(OS_outer, 3, dict_entry);
224 |
225 | return id;
226 | }
227 |
228 | std::string
229 | TemplightProtobufWriter::printTemplateName(const std::string &Name) {
230 |
231 | /*
232 | message TemplateName {
233 | optional string name = 1;
234 | optional bytes compressed_name = 2;
235 | }
236 | */
237 |
238 | std::string tname_contents;
239 | llvm::raw_string_ostream OS_inner(tname_contents);
240 |
241 | switch (compressionMode) {
242 | case 1: { // zlib-compressed name:
243 | llvm::SmallVector CompressedBuffer;
244 | llvm::compression::zlib::compress(llvm::arrayRefFromStringRef(Name),
245 | CompressedBuffer);
246 | // optional bytes compressed_name = 2;
247 | llvm::protobuf::saveString(OS_inner, 2,
248 | llvm::toStringRef(CompressedBuffer));
249 | break;
250 | }
251 | LLVM_FALLTHROUGH;
252 | case 0:
253 | // optional string name = 1;
254 | llvm::protobuf::saveString(OS_inner, 1, Name); // name
255 | break;
256 | case 2:
257 | default:
258 | // optional uint32 dict_id = 3;
259 | llvm::protobuf::saveVarInt(OS_inner, 3, createDictionaryEntry(Name));
260 | break;
261 | }
262 |
263 | OS_inner.str();
264 |
265 | return tname_contents; // NRVO
266 | }
267 |
268 | void TemplightProtobufWriter::printEntry(
269 | const PrintableTemplightEntryBegin &aEntry) {
270 |
271 | std::string entry_contents;
272 | {
273 | llvm::raw_string_ostream OS_inner(entry_contents);
274 |
275 | /*
276 | message Begin {
277 | required SynthesisKind kind = 1;
278 | required string name = 2;
279 | required SourceLocation location = 3;
280 | optional double time_stamp = 4;
281 | optional uint64 memory_usage = 5;
282 | optional SourceLocation template_origin = 6;
283 | }
284 | */
285 |
286 | llvm::protobuf::saveVarInt(OS_inner, 1, aEntry.SynthesisKind); // kind
287 | llvm::protobuf::saveString(OS_inner, 2,
288 | printTemplateName(aEntry.Name)); // name
289 | llvm::protobuf::saveString(OS_inner, 3,
290 | printEntryLocation(aEntry.FileName, aEntry.Line,
291 | aEntry.Column)); // location
292 | llvm::protobuf::saveDouble(OS_inner, 4, aEntry.TimeStamp); // time_stamp
293 | if (aEntry.MemoryUsage > 0)
294 | llvm::protobuf::saveVarInt(OS_inner, 5,
295 | aEntry.MemoryUsage); // memory_usage
296 | if (!aEntry.TempOri_FileName.empty())
297 | llvm::protobuf::saveString(
298 | OS_inner, 6,
299 | printEntryLocation(aEntry.TempOri_FileName, aEntry.TempOri_Line,
300 | aEntry.TempOri_Column)); // template_origin
301 | }
302 |
303 | std::string oneof_contents;
304 | {
305 | llvm::raw_string_ostream OS_inner(oneof_contents);
306 |
307 | /*
308 | oneof begin_or_end {
309 | Begin begin = 1;
310 | End end = 2;
311 | }
312 | */
313 |
314 | llvm::protobuf::saveString(OS_inner, 1, entry_contents); // begin
315 | }
316 |
317 | llvm::raw_string_ostream OS(buffer);
318 |
319 | // repeated TemplightEntry entries = 2;
320 | llvm::protobuf::saveString(OS, 2, oneof_contents);
321 | }
322 |
323 | void TemplightProtobufWriter::printEntry(
324 | const PrintableTemplightEntryEnd &aEntry) {
325 |
326 | std::string entry_contents;
327 | {
328 | llvm::raw_string_ostream OS_inner(entry_contents);
329 |
330 | /*
331 | message End {
332 | optional double time_stamp = 1;
333 | optional uint64 memory_usage = 2;
334 | }
335 | */
336 |
337 | llvm::protobuf::saveDouble(OS_inner, 1, aEntry.TimeStamp); // time_stamp
338 | if (aEntry.MemoryUsage > 0)
339 | llvm::protobuf::saveVarInt(OS_inner, 2,
340 | aEntry.MemoryUsage); // memory_usage
341 | }
342 |
343 | std::string oneof_contents;
344 | {
345 | llvm::raw_string_ostream OS_inner(oneof_contents);
346 |
347 | /*
348 | oneof begin_or_end {
349 | Begin begin = 1;
350 | End end = 2;
351 | }
352 | */
353 |
354 | llvm::protobuf::saveString(OS_inner, 2, entry_contents); // end
355 | }
356 |
357 | llvm::raw_string_ostream OS(buffer);
358 |
359 | // repeated TemplightEntry entries = 2;
360 | llvm::protobuf::saveString(OS, 2, oneof_contents);
361 | }
362 |
363 | } // namespace clang
364 |
--------------------------------------------------------------------------------
/lib/TemplightTracer.cpp:
--------------------------------------------------------------------------------
1 | //===- TemplightTracer.cpp -----------------------*- C++ -*----------------===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #include "TemplightTracer.h"
11 |
12 | #include "PrintableTemplightEntries.h"
13 | #include "TemplightEntryPrinter.h"
14 | #include "TemplightProtobufWriter.h"
15 |
16 | #include
17 | #include
18 | #include
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 |
31 | namespace clang {
32 |
33 | namespace {
34 |
35 | struct RawTemplightTraceEntry {
36 | bool IsTemplateBegin;
37 | std::size_t ParentBeginIdx;
38 | Sema::CodeSynthesisContext::SynthesisKind SynthesisKind;
39 | Decl *Entity;
40 | SourceLocation PointOfInstantiation;
41 | double TimeStamp;
42 | std::uint64_t MemoryUsage;
43 |
44 | static const std::size_t invalid_parent = ~std::size_t(0);
45 |
46 | RawTemplightTraceEntry()
47 | : IsTemplateBegin(true), ParentBeginIdx(invalid_parent),
48 | SynthesisKind(Sema::CodeSynthesisContext::TemplateInstantiation),
49 | Entity(0), TimeStamp(0.0), MemoryUsage(0){};
50 | };
51 |
52 | PrintableTemplightEntryBegin
53 | rawToPrintableBegin(const Sema &TheSema, const RawTemplightTraceEntry &Entry) {
54 | PrintableTemplightEntryBegin Ret;
55 |
56 | Ret.SynthesisKind = Entry.SynthesisKind;
57 |
58 | NamedDecl *NamedTemplate = dyn_cast_or_null(Entry.Entity);
59 | if (NamedTemplate) {
60 | llvm::raw_string_ostream OS(Ret.Name);
61 | NamedTemplate->getNameForDiagnostic(OS, TheSema.getLangOpts(), true);
62 | }
63 |
64 | PresumedLoc Loc =
65 | TheSema.getSourceManager().getPresumedLoc(Entry.PointOfInstantiation);
66 | if (!Loc.isInvalid()) {
67 | Ret.FileName = Loc.getFilename();
68 | Ret.Line = Loc.getLine();
69 | Ret.Column = Loc.getColumn();
70 | } else {
71 | Ret.FileName = "";
72 | Ret.Line = 0;
73 | Ret.Column = 0;
74 | }
75 |
76 | Ret.TimeStamp = Entry.TimeStamp;
77 | Ret.MemoryUsage = Entry.MemoryUsage;
78 |
79 | if (Entry.Entity) {
80 | PresumedLoc Loc =
81 | TheSema.getSourceManager().getPresumedLoc(Entry.Entity->getLocation());
82 | if (!Loc.isInvalid()) {
83 | Ret.TempOri_FileName = Loc.getFilename();
84 | Ret.TempOri_Line = Loc.getLine();
85 | Ret.TempOri_Column = Loc.getColumn();
86 | } else {
87 | Ret.TempOri_FileName = "";
88 | Ret.TempOri_Line = 0;
89 | Ret.TempOri_Column = 0;
90 | }
91 | }
92 |
93 | return Ret;
94 | }
95 |
96 | PrintableTemplightEntryEnd
97 | rawToPrintableEnd(const Sema &TheSema, const RawTemplightTraceEntry &Entry) {
98 | return {Entry.TimeStamp, Entry.MemoryUsage};
99 | }
100 |
101 | } // unnamed namespace
102 |
103 | class TemplightTracer::TracePrinter : public TemplightEntryPrinter {
104 | public:
105 | void skipRawEntry(const RawTemplightTraceEntry &Entry) { skipEntry(); }
106 |
107 | bool shouldIgnoreRawEntry(const RawTemplightTraceEntry &Entry) {
108 |
109 | // Avoid some duplication of memoization entries:
110 | if ((Entry.SynthesisKind == Sema::CodeSynthesisContext::Memoization) &&
111 | LastClosedMemoization && (LastClosedMemoization == Entry.Entity)) {
112 | return true;
113 | }
114 |
115 | // if we have an end entry, we must ensure it corresponds to the current
116 | // begin entry:
117 | // these checks are a bit redundant and overly cautious, but better safe
118 | // than sorry when sanitizing.
119 | if ((!Entry.IsTemplateBegin) &&
120 | ((TraceEntries.empty()) ||
121 | (CurrentParentBegin == RawTemplightTraceEntry::invalid_parent) ||
122 | (CurrentParentBegin >= TraceEntries.size()) ||
123 | !((TraceEntries[CurrentParentBegin].SynthesisKind ==
124 | Entry.SynthesisKind) &&
125 | (TraceEntries[CurrentParentBegin].Entity == Entry.Entity)))) {
126 | return true; // ignore end entries that don't match the current begin
127 | // entry.
128 | }
129 |
130 | return false;
131 | };
132 |
133 | void printOrSkipEntry(RawTemplightTraceEntry &Entry) {
134 | if (IgnoreSystemFlag && !Entry.PointOfInstantiation.isInvalid() &&
135 | TheSema.getSourceManager().isInSystemHeader(
136 | Entry.PointOfInstantiation)) {
137 | skipRawEntry(
138 | Entry); // recursively skip all entries until end of this one.
139 | } else {
140 | if (Entry.IsTemplateBegin) {
141 | printEntry(rawToPrintableBegin(TheSema, Entry));
142 | } else {
143 | printEntry(rawToPrintableEnd(TheSema, Entry));
144 | }
145 | }
146 | };
147 |
148 | void printCachedRawEntries() {
149 | for (std::vector::iterator it =
150 | TraceEntries.begin();
151 | it != TraceEntries.end(); ++it)
152 | printOrSkipEntry(*it);
153 | TraceEntries.clear();
154 | CurrentParentBegin = RawTemplightTraceEntry::invalid_parent;
155 | };
156 |
157 | void printRawEntry(RawTemplightTraceEntry Entry, bool inSafeMode = false) {
158 | if (shouldIgnoreRawEntry(Entry))
159 | return;
160 |
161 | if (inSafeMode)
162 | printOrSkipEntry(Entry);
163 |
164 | // Always maintain a stack of cached trace entries such that the sanity of
165 | // the traces can be enforced.
166 | if (Entry.IsTemplateBegin) {
167 | Entry.ParentBeginIdx = CurrentParentBegin;
168 | CurrentParentBegin = TraceEntries.size();
169 | } else { // note: this point should not be reached if CurrentParentBegin is
170 | // not valid.
171 | Entry.ParentBeginIdx = TraceEntries[CurrentParentBegin].ParentBeginIdx;
172 | CurrentParentBegin = Entry.ParentBeginIdx;
173 | };
174 | TraceEntries.push_back(Entry);
175 |
176 | if (Entry.IsTemplateBegin)
177 | LastClosedMemoization = nullptr;
178 | if (!Entry.IsTemplateBegin &&
179 | (Entry.SynthesisKind == Sema::CodeSynthesisContext::Memoization))
180 | LastClosedMemoization = Entry.Entity;
181 |
182 | if (!Entry.IsTemplateBegin &&
183 | (Entry.SynthesisKind == TraceEntries.front().SynthesisKind) &&
184 | (Entry.Entity ==
185 | TraceEntries.front()
186 | .Entity)) { // did we reach the end of the top-level begin entry?
187 | if (!inSafeMode) { // if not in safe-mode, print out the cached entries.
188 | printCachedRawEntries();
189 | } else { // if in safe-mode, simply clear the cached entries.
190 | TraceEntries.clear();
191 | CurrentParentBegin = RawTemplightTraceEntry::invalid_parent;
192 | }
193 | }
194 | };
195 |
196 | void startTrace() {
197 | // get the source name from the source manager:
198 | std::string src_name = "a";
199 | FileID fileID = TheSema.getSourceManager().getMainFileID();
200 | OptionalFileEntryRef file_ref =
201 | TheSema.getSourceManager().getFileEntryRefForID(fileID);
202 | if (file_ref.has_value()) {
203 | src_name = file_ref->getName().str();
204 | }
205 | initialize(src_name);
206 | };
207 |
208 | void endTrace() {
209 | printCachedRawEntries();
210 | finalize();
211 | };
212 |
213 | TracePrinter(const Sema &aSema, const std::string &Output,
214 | bool IgnoreSystem = false)
215 | : TemplightEntryPrinter(Output), TheSema(aSema),
216 | LastClosedMemoization(nullptr),
217 | CurrentParentBegin(RawTemplightTraceEntry::invalid_parent),
218 | IgnoreSystemFlag(IgnoreSystem){};
219 |
220 | ~TracePrinter(){};
221 |
222 | const Sema &TheSema;
223 |
224 | std::vector TraceEntries;
225 | Decl *LastClosedMemoization;
226 | std::size_t CurrentParentBegin;
227 |
228 | unsigned IgnoreSystemFlag : 1;
229 | };
230 |
231 | void TemplightTracer::atTemplateBegin(const Sema &TheSema,
232 | const Sema::CodeSynthesisContext &Inst) {
233 | if (!Printer)
234 | return;
235 |
236 | RawTemplightTraceEntry Entry;
237 |
238 | Entry.IsTemplateBegin = true;
239 | Entry.SynthesisKind = Inst.Kind;
240 | Entry.Entity = Inst.Entity;
241 | Entry.PointOfInstantiation = Inst.PointOfInstantiation;
242 |
243 | // NOTE: Use this function because it produces time since start of process.
244 | llvm::sys::TimePoint<> now;
245 | std::chrono::nanoseconds user, sys;
246 | llvm::sys::Process::GetTimeUsage(now, user, sys);
247 | if (user != std::chrono::nanoseconds::zero())
248 | now = llvm::sys::TimePoint<>(user);
249 |
250 | using Seconds = std::chrono::duration>;
251 | Entry.TimeStamp = Seconds(now.time_since_epoch()).count();
252 | Entry.MemoryUsage = (MemoryFlag ? llvm::sys::Process::GetMallocUsage() : 0);
253 |
254 | Printer->printRawEntry(Entry, SafeModeFlag);
255 | }
256 |
257 | void TemplightTracer::atTemplateEnd(const Sema &TheSema,
258 | const Sema::CodeSynthesisContext &Inst) {
259 | if (!Printer)
260 | return;
261 |
262 | RawTemplightTraceEntry Entry;
263 |
264 | Entry.IsTemplateBegin = false;
265 | Entry.SynthesisKind = Inst.Kind;
266 | Entry.Entity = Inst.Entity;
267 |
268 | // NOTE: Use this function because it produces time since start of process.
269 | llvm::sys::TimePoint<> now;
270 | std::chrono::nanoseconds user, sys;
271 | llvm::sys::Process::GetTimeUsage(now, user, sys);
272 | if (user != std::chrono::nanoseconds::zero())
273 | now = llvm::sys::TimePoint<>(user);
274 |
275 | using Seconds = std::chrono::duration>;
276 | Entry.TimeStamp = Seconds(now.time_since_epoch()).count();
277 | Entry.MemoryUsage = (MemoryFlag ? llvm::sys::Process::GetMallocUsage() : 0);
278 |
279 | Printer->printRawEntry(Entry, SafeModeFlag);
280 | }
281 |
282 | TemplightTracer::TemplightTracer(const Sema &TheSema, std::string Output,
283 | bool Memory, bool Safemode, bool IgnoreSystem)
284 | : MemoryFlag(Memory), SafeModeFlag(Safemode) {
285 |
286 | Printer.reset(
287 | new TemplightTracer::TracePrinter(TheSema, Output, IgnoreSystem));
288 |
289 | if (!Printer->getTraceStream()) {
290 | llvm::errs()
291 | << "Error: [Templight-Tracer] Failed to create template trace file!";
292 | Printer.reset();
293 | llvm::errs() << "Note: [Templight] Template trace has been disabled.";
294 | return;
295 | }
296 |
297 | Printer->takeWriter(
298 | new clang::TemplightProtobufWriter(*Printer->getTraceStream()));
299 | }
300 |
301 | TemplightTracer::~TemplightTracer() {
302 | // must be defined here due to TracePrinter being incomplete in header.
303 | }
304 |
305 | void TemplightTracer::initialize(const Sema &) {
306 | if (Printer)
307 | Printer->startTrace();
308 | }
309 |
310 | void TemplightTracer::finalize(const Sema &) {
311 | if (Printer)
312 | Printer->endTrace();
313 | }
314 |
315 | void TemplightTracer::readBlacklists(const std::string &BLFilename) {
316 | if (Printer)
317 | Printer->readBlacklists(BLFilename);
318 | }
319 |
320 | } // namespace clang
321 |
--------------------------------------------------------------------------------
/templight_clang_patch.diff:
--------------------------------------------------------------------------------
1 | diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
2 | index 03b43ddd..f22af830 100644
3 | --- a/include/clang/Driver/CC1Options.td
4 | +++ b/include/clang/Driver/CC1Options.td
5 | @@ -501,6 +501,8 @@ def ftest_module_file_extension_EQ :
6 | "The argument is parsed as blockname:major:minor:hashed:user info">;
7 | def fconcepts_ts : Flag<["-"], "fconcepts-ts">,
8 | HelpText<"Enable C++ Extensions for Concepts.">;
9 | +def templight_profile : Flag<["-"], "templight-profile">,
10 | + HelpText<"Add timestamps to the templight-dump output">;
11 |
12 | let Group = Action_Group in {
13 |
14 | diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
15 | index 768957ac..e1d4908c 100644
16 | --- a/include/clang/Frontend/FrontendOptions.h
17 | +++ b/include/clang/Frontend/FrontendOptions.h
18 | @@ -301,6 +301,10 @@ public:
19 |
20 | /// Whether timestamps should be written to the produced PCH file.
21 | unsigned IncludeTimestamps : 1;
22 | +
23 | + /// Whether to add additional
24 | + /// information to Templight dumps.
25 | + unsigned TemplightProfile : 1;
26 |
27 | CodeCompleteOptions CodeCompleteOpts;
28 |
29 | @@ -447,7 +451,8 @@ public:
30 | SkipFunctionBodies(false), UseGlobalModuleIndex(true),
31 | GenerateGlobalModuleIndex(true), ASTDumpDecls(false),
32 | ASTDumpLookups(false), BuildingImplicitModule(false),
33 | - ModulesEmbedAllFiles(false), IncludeTimestamps(true) {}
34 | + ModulesEmbedAllFiles(false), IncludeTimestamps(true),
35 | + TemplightProfile(false) {}
36 |
37 | /// getInputKindForExtension - Return the appropriate input kind for a file
38 | /// extension. For example, "c" would return InputKind::C.
39 | diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
40 | index 67e15b41..19ef1194 100644
41 | --- a/lib/Frontend/CompilerInvocation.cpp
42 | +++ b/lib/Frontend/CompilerInvocation.cpp
43 | @@ -1509,6 +1509,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
44 | Opts.ModulesEmbedFiles = Args.getAllArgValues(OPT_fmodules_embed_file_EQ);
45 | Opts.ModulesEmbedAllFiles = Args.hasArg(OPT_fmodules_embed_all_files);
46 | Opts.IncludeTimestamps = !Args.hasArg(OPT_fno_pch_timestamp);
47 | + Opts.TemplightProfile = Args.hasArg(OPT_templight_profile);
48 |
49 | Opts.CodeCompleteOpts.IncludeMacros
50 | = Args.hasArg(OPT_code_completion_macros);
51 | diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
52 | index 8cb6a042..5cb70482 100644
53 | --- a/lib/Frontend/FrontendActions.cpp
54 | +++ b/lib/Frontend/FrontendActions.cpp
55 | @@ -26,6 +26,7 @@
56 | #include "llvm/Support/Path.h"
57 | #include "llvm/Support/raw_ostream.h"
58 | #include "llvm/Support/YAMLTraits.h"
59 | +#include
60 | #include
61 | #include
62 |
63 | @@ -288,19 +289,14 @@ struct TemplightEntry {
64 | std::string Event;
65 | std::string DefinitionLocation;
66 | std::string PointOfInstantiation;
67 | + Optional TimeStamp;
68 | };
69 | } // namespace
70 |
71 | namespace llvm {
72 | namespace yaml {
73 | template <> struct MappingTraits {
74 | - static void mapping(IO &io, TemplightEntry &fields) {
75 | - io.mapRequired("name", fields.Name);
76 | - io.mapRequired("kind", fields.Kind);
77 | - io.mapRequired("event", fields.Event);
78 | - io.mapRequired("orig", fields.DefinitionLocation);
79 | - io.mapRequired("poi", fields.PointOfInstantiation);
80 | - }
81 | + static void mapping(IO &io, TemplightEntry &fields);
82 | };
83 | } // namespace yaml
84 | } // namespace llvm
85 | @@ -312,19 +308,46 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
86 | public:
87 | void initialize(const Sema &) override {}
88 |
89 | - void finalize(const Sema &) override {}
90 | + void finalize(const Sema &) override {
91 | + if(isProfilingEnabled())
92 | + for(auto &Entry : *TemplightEntries)
93 | + displayTemplightEntry(llvm::outs(), Entry);
94 | + }
95 |
96 | void atTemplateBegin(const Sema &TheSema,
97 | const CodeSynthesisContext &Inst) override {
98 | - displayTemplightEntry(llvm::outs(), TheSema, Inst);
99 | + TemplightEntry Entry = getTemplightEntry(TheSema, Inst);
100 | +
101 | + if(isProfilingEnabled())
102 | + TemplightEntries->push_back(std::move(Entry));
103 | + else
104 | + displayTemplightEntry(llvm::outs(), Entry);
105 | }
106 |
107 | void atTemplateEnd(const Sema &TheSema,
108 | const CodeSynthesisContext &Inst) override {
109 | - displayTemplightEntry(llvm::outs(), TheSema, Inst);
110 | + TemplightEntry Entry = getTemplightEntry(TheSema, Inst);
111 | +
112 | + if(isProfilingEnabled())
113 | + TemplightEntries->push_back(std::move(Entry));
114 | + else
115 | + displayTemplightEntry(llvm::outs(), Entry);
116 | + }
117 | +
118 | + void enableProfiling() {
119 | + TemplightEntries = std::vector();
120 | }
121 | +
122 | + bool isProfilingEnabled() {
123 | + return TemplightEntries.hasValue();
124 | + }
125 | +
126 | + static const std::chrono::time_point start;
127 |
128 | private:
129 | +
130 | + Optional> TemplightEntries = None;
131 | +
132 | static std::string toString(CodeSynthesisContext::SynthesisKind Kind) {
133 | switch (Kind) {
134 | case CodeSynthesisContext::TemplateInstantiation:
135 | @@ -353,15 +376,12 @@ private:
136 | return "";
137 | }
138 |
139 | - template
140 | - static void displayTemplightEntry(llvm::raw_ostream &Out, const Sema &TheSema,
141 | - const CodeSynthesisContext &Inst) {
142 | + void displayTemplightEntry(llvm::raw_ostream &Out,
143 | + TemplightEntry& Entry) {
144 | std::string YAML;
145 | {
146 | llvm::raw_string_ostream OS(YAML);
147 | llvm::yaml::Output YO(OS);
148 | - TemplightEntry Entry =
149 | - getTemplightEntry(TheSema, Inst);
150 | llvm::yaml::EmptyContext Context;
151 | llvm::yaml::yamlize(YO, Entry, true, Context);
152 | }
153 | @@ -369,9 +389,13 @@ private:
154 | }
155 |
156 | template
157 | - static TemplightEntry getTemplightEntry(const Sema &TheSema,
158 | + TemplightEntry getTemplightEntry(const Sema &TheSema,
159 | const CodeSynthesisContext &Inst) {
160 | TemplightEntry Entry;
161 | + if (isProfilingEnabled()){
162 | + auto end = std::chrono::high_resolution_clock::now();
163 | + Entry.TimeStamp = std::chrono::nanoseconds(end-start).count();
164 | + }
165 | Entry.Kind = toString(Inst.Kind);
166 | Entry.Event = BeginInstantiation ? "Begin" : "End";
167 | if (auto *NamedTemplate = dyn_cast_or_null(Inst.Entity)) {
168 | @@ -394,8 +418,27 @@ private:
169 | return Entry;
170 | }
171 | };
172 | +
173 | +const std::chrono::time_point
174 | + DefaultTemplateInstCallback::start = std::chrono::high_resolution_clock::now();
175 | +
176 | } // namespace
177 |
178 | +namespace llvm {
179 | +namespace yaml {
180 | +void MappingTraits::mapping(IO &io, TemplightEntry &fields)
181 | +{
182 | + io.mapRequired("name", fields.Name);
183 | + io.mapRequired("kind", fields.Kind);
184 | + io.mapRequired("event", fields.Event);
185 | + io.mapRequired("orig", fields.DefinitionLocation);
186 | + io.mapRequired("poi", fields.PointOfInstantiation);
187 | + if(fields.TimeStamp)
188 | + io.mapRequired("stamp", fields.TimeStamp.getValue());
189 | +}
190 | +} // namespace yaml
191 | +} // namespace llvm
192 | +
193 | std::unique_ptr
194 | TemplightDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
195 | return llvm::make_unique();
196 | @@ -410,8 +453,11 @@ void TemplightDumpAction::ExecuteAction() {
197 | // here so the source manager would be initialized.
198 | EnsureSemaIsCreated(CI, *this);
199 |
200 | - CI.getSema().TemplateInstCallbacks.push_back(
201 | - llvm::make_unique());
202 | + auto D = llvm::make_unique();
203 | + if(CI.getFrontendOpts().TemplightProfile)
204 | + D->enableProfiling();
205 | +
206 | + CI.getSema().TemplateInstCallbacks.push_back(std::move(D));
207 | ASTFrontendAction::ExecuteAction();
208 | }
209 |
210 |
--------------------------------------------------------------------------------
/templight_clang_version.txt:
--------------------------------------------------------------------------------
1 | 'templight_clang_patch*.diff' was created using the following LLVM/Clang versions:
2 |
3 | LLVM git: 7256bf169ac3709b3c3ad5c6d541cf809ec341fb
4 | LLVM svn: https://llvm.org/svn/llvm-project/llvm/trunk@330373
5 | Clang git: c33e1469f018cf71327e06df054a0ffc87f4d9f8
6 | Clang svn: https://llvm.org/svn/llvm-project/cfe/trunk@330382
7 |
--------------------------------------------------------------------------------
/templight_driver.cpp:
--------------------------------------------------------------------------------
1 | //===-- templight_driver.cpp ------------------------------*- C++ -*-------===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 | //
10 | // This is the entry point to the templight driver; it is a thin wrapper
11 | // for functionality in the Driver clang library with modifications to invoke
12 | // Templight.
13 | //
14 | //===----------------------------------------------------------------------===//
15 |
16 | #include "clang/Basic/CharInfo.h"
17 | #include "clang/Basic/DiagnosticOptions.h"
18 | #include "clang/Config/config.h"
19 | #include "clang/Driver/Action.h"
20 | #include "clang/Driver/Compilation.h"
21 | #include "clang/Driver/Driver.h"
22 | #include "clang/Driver/DriverDiagnostic.h"
23 | #include "clang/Driver/Options.h"
24 | #include "clang/Driver/Tool.h"
25 | #include "clang/Frontend/ChainedDiagnosticConsumer.h"
26 | #include "clang/Frontend/CompilerInstance.h"
27 | #include "clang/Frontend/CompilerInvocation.h"
28 | #include "clang/Frontend/FrontendDiagnostic.h" // IWYU pragma: keep
29 | #include "clang/Frontend/SerializedDiagnosticPrinter.h"
30 | #include "clang/Frontend/TextDiagnosticPrinter.h"
31 | #include "clang/Frontend/Utils.h"
32 | #include "clang/FrontendTool/Utils.h"
33 | #include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
34 | #include "llvm/ADT/ArrayRef.h"
35 | #include "llvm/ADT/STLExtras.h"
36 | #include "llvm/ADT/SmallString.h"
37 | #include "llvm/ADT/SmallVector.h"
38 | #include "llvm/ADT/Statistic.h"
39 | #include "llvm/Config/llvm-config.h"
40 | #include "llvm/MC/TargetRegistry.h"
41 | #include "llvm/Option/ArgList.h"
42 | #include "llvm/Option/OptTable.h"
43 | #include "llvm/Option/Option.h"
44 | #include "llvm/Support/CommandLine.h"
45 | #include "llvm/Support/DynamicLibrary.h"
46 | #include "llvm/Support/ErrorHandling.h"
47 | #include "llvm/Support/FileSystem.h"
48 | #include "llvm/Support/InitLLVM.h"
49 | #include "llvm/Support/ManagedStatic.h"
50 | #include "llvm/Support/MemoryBuffer.h"
51 | #include "llvm/Support/Path.h"
52 | #include "llvm/Support/Process.h"
53 | #include "llvm/Support/Program.h"
54 | #include "llvm/Support/Regex.h"
55 | #include "llvm/Support/Signals.h"
56 | #include "llvm/Support/StringSaver.h"
57 | #include "llvm/Support/TargetSelect.h"
58 | #include "llvm/Support/Timer.h"
59 | #include "llvm/Support/raw_ostream.h"
60 | #include "llvm/TargetParser/Host.h"
61 |
62 | #include "TemplightAction.h"
63 |
64 | #include
65 | #include
66 | #include
67 |
68 | using namespace clang;
69 | using namespace clang::driver;
70 | using namespace llvm::opt;
71 | using namespace llvm;
72 |
73 | // Mark all Templight options with this category, everything else will be
74 | // handled as clang driver options.
75 | static cl::OptionCategory
76 | ClangTemplightCategory("Templight options (USAGE: templight [[-Xtemplight "
77 | "[templight option]]|[options]] )");
78 |
79 | static cl::opt OutputToStdOut(
80 | "stdout",
81 | cl::desc("Output template instantiation traces to standard output."),
82 | cl::cat(ClangTemplightCategory));
83 |
84 | static cl::opt MemoryProfile(
85 | "memory",
86 | cl::desc("Profile the memory usage during template instantiations."),
87 | cl::cat(ClangTemplightCategory));
88 |
89 | static cl::opt OutputInSafeMode(
90 | "safe-mode",
91 | cl::desc("Output Templight traces without buffering, \n"
92 | "not to lose them at failure (note: this will \n"
93 | "distort the timing profiles due to file I/O latency)."),
94 | cl::cat(ClangTemplightCategory));
95 |
96 | static cl::opt
97 | IgnoreSystemInst("ignore-system",
98 | cl::desc("Ignore any template instantiation coming from \n"
99 | "system-includes (-isystem)."),
100 | cl::cat(ClangTemplightCategory));
101 |
102 | static cl::opt
103 | InstProfiler("profiler",
104 | cl::desc("Start an interactive Templight debugging session."),
105 | cl::cat(ClangTemplightCategory));
106 |
107 | static cl::opt InteractiveDebug(
108 | "debugger", cl::desc("Start an interactive Templight debugging session."),
109 | cl::cat(ClangTemplightCategory));
110 |
111 | static cl::opt
112 | OutputFilename("output",
113 | cl::desc("Write Templight profiling traces to ."),
114 | cl::cat(ClangTemplightCategory));
115 |
116 | static std::string LocalOutputFilename;
117 | static SmallVector TempOutputFiles;
118 |
119 | static cl::opt BlackListFilename(
120 | "blacklist",
121 | cl::desc(
122 | "Use regex expressions in to filter out undesirable traces."),
123 | cl::cat(ClangTemplightCategory));
124 |
125 | static cl::Option *TemplightOptions[] = {
126 | &OutputToStdOut, &MemoryProfile, &OutputInSafeMode, &IgnoreSystemInst,
127 | &InstProfiler, &InteractiveDebug, &OutputFilename, &BlackListFilename};
128 |
129 | void PrintTemplightHelp() {
130 | // Compute the maximum argument length...
131 | const std::size_t TemplightOptNum =
132 | sizeof(TemplightOptions) / sizeof(cl::Option *);
133 | std::size_t MaxArgLen = 0;
134 | for (std::size_t i = 0, e = TemplightOptNum; i != e; ++i) {
135 | MaxArgLen = std::max(MaxArgLen, TemplightOptions[i]->getOptionWidth());
136 | }
137 |
138 | llvm::outs() << '\n' << ClangTemplightCategory.getName() << "\n\n";
139 |
140 | for (std::size_t i = 0, e = TemplightOptNum; i != e; ++i) {
141 | TemplightOptions[i]->printOptionInfo(MaxArgLen);
142 | }
143 | llvm::outs() << '\n';
144 | }
145 |
146 | std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
147 | if (!CanonicalPrefixes) {
148 | SmallString<128> ExecutablePath(Argv0);
149 | // Do a PATH lookup if Argv0 isn't a valid path.
150 | if (!llvm::sys::fs::exists(ExecutablePath)) {
151 | if (llvm::ErrorOr P =
152 | llvm::sys::findProgramByName(ExecutablePath)) {
153 | ExecutablePath = *P;
154 | }
155 | }
156 | return std::string(ExecutablePath.str());
157 | }
158 |
159 | // This just needs to be some symbol in the binary; C++ doesn't
160 | // allow taking the address of ::main however.
161 | void *P = (void*) (intptr_t) GetExecutablePath;
162 | return llvm::sys::fs::getMainExecutable(Argv0, P);
163 | }
164 |
165 | static const char *GetStableCStr(llvm::StringSet<> &SavedStrings, StringRef S) {
166 | return SavedStrings.insert(S).first->getKeyData();
167 | }
168 |
169 | struct DriverSuffix {
170 | const char *Suffix;
171 | const char *ModeFlag;
172 | };
173 |
174 | static const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) {
175 | // A list of known driver suffixes. Suffixes are compared against the
176 | // program name in order. If there is a match, the frontend type if updated as
177 | // necessary by applying the ModeFlag.
178 | static const DriverSuffix DriverSuffixes[] = {
179 | {"templight", nullptr},
180 | {"templight++", "--driver-mode=g++"},
181 | {"templight-c++", "--driver-mode=g++"},
182 | {"templight-cc", nullptr},
183 | {"templight-cpp", "--driver-mode=cpp"},
184 | {"templight-g++", "--driver-mode=g++"},
185 | {"templight-gcc", nullptr},
186 | {"templight-cl", "--driver-mode=cl"},
187 | {"cc", nullptr},
188 | {"cpp", "--driver-mode=cpp"},
189 | {"cl", "--driver-mode=cl"},
190 | {"++", "--driver-mode=g++"},
191 | };
192 |
193 | for (const auto &DS : DriverSuffixes) {
194 | StringRef Suffix(DS.Suffix);
195 | if (ProgName.ends_with(Suffix)) {
196 | Pos = ProgName.size() - Suffix.size();
197 | return &DS;
198 | }
199 | }
200 | return nullptr;
201 | }
202 |
203 | /// Normalize the program name from argv[0] by stripping the file extension if
204 | /// present and lower-casing the string on Windows.
205 | static std::string normalizeProgramName(llvm::StringRef Argv0) {
206 | std::string ProgName = std::string(llvm::sys::path::filename(Argv0));
207 | if (is_style_windows(llvm::sys::path::Style::native)) {
208 | // Transform to lowercase for case insensitive file systems.
209 | std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(),
210 | ::tolower);
211 | }
212 | return ProgName;
213 | }
214 |
215 | static const DriverSuffix *parseDriverSuffix(StringRef ProgName, size_t &Pos) {
216 | // Try to infer frontend type and default target from the program name by
217 | // comparing it against DriverSuffixes in order.
218 |
219 | // If there is a match, the function tries to identify a target as prefix.
220 | // E.g. "x86_64-linux-clang" as interpreted as suffix "clang" with target
221 | // prefix "x86_64-linux". If such a target prefix is found, it may be
222 | // added via -target as implicit first argument.
223 | const DriverSuffix *DS = FindDriverSuffix(ProgName, Pos);
224 |
225 | if (!DS && ProgName.ends_with(".exe")) {
226 | // Try again after stripping the executable suffix:
227 | // clang++.exe -> clang++
228 | ProgName = ProgName.drop_back(StringRef(".exe").size());
229 | DS = FindDriverSuffix(ProgName, Pos);
230 | }
231 |
232 | if (!DS) {
233 | // Try again after stripping any trailing version number:
234 | // clang++3.5 -> clang++
235 | ProgName = ProgName.rtrim("0123456789.");
236 | DS = FindDriverSuffix(ProgName, Pos);
237 | }
238 |
239 | if (!DS) {
240 | // Try again after stripping trailing -component.
241 | // clang++-tot -> clang++
242 | ProgName = ProgName.slice(0, ProgName.rfind('-'));
243 | DS = FindDriverSuffix(ProgName, Pos);
244 | }
245 | return DS;
246 | }
247 |
248 | ParsedClangName getTargetAndModeFromProgramName(StringRef PN) {
249 | std::string ProgName = normalizeProgramName(PN);
250 | size_t SuffixPos;
251 | const DriverSuffix *DS = parseDriverSuffix(ProgName, SuffixPos);
252 | if (!DS)
253 | return {};
254 | size_t SuffixEnd = SuffixPos + strlen(DS->Suffix);
255 |
256 | size_t LastComponent = ProgName.rfind('-', SuffixPos);
257 | if (LastComponent == std::string::npos)
258 | return ParsedClangName(ProgName.substr(0, SuffixEnd), DS->ModeFlag);
259 | std::string ModeSuffix = ProgName.substr(LastComponent + 1,
260 | SuffixEnd - LastComponent - 1);
261 |
262 | // Infer target from the prefix.
263 | StringRef Prefix(ProgName);
264 | Prefix = Prefix.slice(0, LastComponent);
265 | std::string IgnoredError;
266 | bool IsRegistered =
267 | llvm::TargetRegistry::lookupTarget(std::string(Prefix), IgnoredError);
268 | return ParsedClangName{std::string(Prefix), ModeSuffix, DS->ModeFlag,
269 | IsRegistered};
270 | }
271 |
272 | static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
273 | SmallVectorImpl &ArgVector,
274 | llvm::StringSet<> &SavedStrings) {
275 | // Put target and mode arguments at the start of argument list so that
276 | // arguments specified in command line could override them. Avoid putting
277 | // them at index 0, as an option like '-cc1' must remain the first.
278 | int InsertionPoint = 0;
279 | if (ArgVector.size() > 0)
280 | ++InsertionPoint;
281 |
282 | if (NameParts.DriverMode) {
283 | // Add the mode flag to the arguments.
284 | ArgVector.insert(ArgVector.begin() + InsertionPoint,
285 | GetStableCStr(SavedStrings, NameParts.DriverMode));
286 | }
287 |
288 | if (NameParts.TargetIsValid) {
289 | const char *arr[] = {"-target", GetStableCStr(SavedStrings,
290 | NameParts.TargetPrefix)};
291 | ArgVector.insert(ArgVector.begin() + InsertionPoint,
292 | std::begin(arr), std::end(arr));
293 | }
294 | }
295 |
296 | static void getCLEnvVarOptions(std::string &EnvValue, llvm::StringSaver &Saver,
297 | SmallVectorImpl &Opts) {
298 | llvm::cl::TokenizeWindowsCommandLine(EnvValue, Saver, Opts);
299 | // The first instance of '#' should be replaced with '=' in each option.
300 | for (const char *Opt : Opts) {
301 | if (char *NumberSignPtr = const_cast(::strchr(Opt, '#'))) {
302 | *NumberSignPtr = '=';
303 | }
304 | }
305 | }
306 |
307 | template
308 | static T checkEnvVar(const char *EnvOptSet, const char *EnvOptFile,
309 | std::string &OptFile) {
310 | const char *Str = ::getenv(EnvOptSet);
311 | if (!Str) {
312 | return T{};
313 | }
314 |
315 | T OptVal = Str;
316 | if (const char *Var = ::getenv(EnvOptFile)) {
317 | OptFile = Var;
318 | }
319 | return OptVal;
320 | }
321 |
322 | static bool SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) {
323 | TheDriver.CCPrintOptions =
324 | checkEnvVar("CC_PRINT_OPTIONS", "CC_PRINT_OPTIONS_FILE",
325 | TheDriver.CCPrintOptionsFilename);
326 | if (checkEnvVar("CC_PRINT_HEADERS", "CC_PRINT_HEADERS_FILE",
327 | TheDriver.CCPrintHeadersFilename)) {
328 | TheDriver.CCPrintHeadersFormat = HIFMT_Textual;
329 | TheDriver.CCPrintHeadersFiltering = HIFIL_None;
330 | } else {
331 | std::string EnvVar = checkEnvVar(
332 | "CC_PRINT_HEADERS_FORMAT", "CC_PRINT_HEADERS_FILE",
333 | TheDriver.CCPrintHeadersFilename);
334 | if (!EnvVar.empty()) {
335 | TheDriver.CCPrintHeadersFormat =
336 | stringToHeaderIncludeFormatKind(EnvVar.c_str());
337 | if (!TheDriver.CCPrintHeadersFormat) {
338 | TheDriver.Diag(clang::diag::err_drv_print_header_env_var)
339 | << 0 << EnvVar;
340 | return false;
341 | }
342 |
343 | const char *FilteringStr = ::getenv("CC_PRINT_HEADERS_FILTERING");
344 | HeaderIncludeFilteringKind Filtering;
345 | if (!stringToHeaderIncludeFiltering(FilteringStr, Filtering)) {
346 | TheDriver.Diag(clang::diag::err_drv_print_header_env_var)
347 | << 1 << FilteringStr;
348 | return false;
349 | }
350 |
351 | if ((TheDriver.CCPrintHeadersFormat == HIFMT_Textual &&
352 | Filtering != HIFIL_None) ||
353 | (TheDriver.CCPrintHeadersFormat == HIFMT_JSON &&
354 | Filtering != HIFIL_Only_Direct_System)) {
355 | TheDriver.Diag(clang::diag::err_drv_print_header_env_var_combination)
356 | << EnvVar << FilteringStr;
357 | return false;
358 | }
359 | TheDriver.CCPrintHeadersFiltering = Filtering;
360 | }
361 | }
362 |
363 | TheDriver.CCLogDiagnostics =
364 | checkEnvVar("CC_LOG_DIAGNOSTICS", "CC_LOG_DIAGNOSTICS_FILE",
365 | TheDriver.CCLogDiagnosticsFilename);
366 | TheDriver.CCPrintProcessStats =
367 | checkEnvVar("CC_PRINT_PROC_STAT", "CC_PRINT_PROC_STAT_FILE",
368 | TheDriver.CCPrintStatReportFilename);
369 | TheDriver.CCPrintInternalStats =
370 | checkEnvVar("CC_PRINT_INTERNAL_STAT", "CC_PRINT_INTERNAL_STAT_FILE",
371 | TheDriver.CCPrintInternalStatReportFilename);
372 |
373 | return true;
374 | }
375 |
376 | static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient,
377 | const std::string &Path) {
378 | // If the templight binary happens to be named cl.exe for compatibility
379 | // reasons, use templight-cl.exe as the prefix to avoid confusion between
380 | // templight and MSVC.
381 | StringRef ExeBasename(llvm::sys::path::filename(Path));
382 | if (ExeBasename.equals_insensitive("cl.exe")) {
383 | ExeBasename = "templight-cl.exe";
384 | }
385 | DiagClient->setPrefix(ExeBasename.str());
386 | }
387 |
388 | static int ExecuteTemplightInvocation(CompilerInstance *Clang) {
389 | // Honor -help.
390 | if (Clang->getFrontendOpts().ShowHelp) {
391 |
392 | // Print the help for the general clang options:
393 | getDriverOptTable().printHelp(
394 | llvm::outs(), "templight",
395 | "Template Profiler and Debugger based on LLVM 'Clang' "
396 | "Compiler: http://clang.llvm.org",
397 | /*Include=*/clang::driver::options::CC1Option, /*Exclude=*/0, false);
398 |
399 | return 0;
400 | }
401 |
402 | // Honor -version.
403 | //
404 | // FIXME: Use a better -version message?
405 | if (Clang->getFrontendOpts().ShowVersion) {
406 | llvm::cl::PrintVersionMessage();
407 | return 0;
408 | }
409 |
410 | // Load any requested plugins.
411 | for (unsigned i = 0, e = Clang->getFrontendOpts().Plugins.size(); i != e;
412 | ++i) {
413 | const std::string &Path = Clang->getFrontendOpts().Plugins[i];
414 | std::string Error;
415 | if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(), &Error))
416 | Clang->getDiagnostics().Report(diag::err_fe_unable_to_load_plugin)
417 | << Path << Error;
418 | }
419 |
420 | // Honor -mllvm.
421 | //
422 | // FIXME: Remove this, one day.
423 | // This should happen AFTER plugins have been loaded!
424 | if (!Clang->getFrontendOpts().LLVMArgs.empty()) {
425 | unsigned NumArgs = Clang->getFrontendOpts().LLVMArgs.size();
426 | std::vector Args(NumArgs + 2);
427 | Args[0] = "clang (LLVM option parsing)";
428 | for (unsigned i = 0; i != NumArgs; ++i)
429 | Args[i + 1] = Clang->getFrontendOpts().LLVMArgs[i].c_str();
430 | Args[NumArgs + 1] = nullptr;
431 | llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.data());
432 | }
433 |
434 | // If there were errors in processing arguments, don't do anything else.
435 | if (Clang->getDiagnostics().hasErrorOccurred())
436 | return 1;
437 |
438 | // Create and execute the frontend action.
439 | std::unique_ptr Act(
440 | new TemplightAction(CreateFrontendAction(*Clang)));
441 | if (!Act)
442 | return 1;
443 |
444 | // Setting up templight action object parameters...
445 | Act->InstProfiler = InstProfiler;
446 | Act->OutputToStdOut = OutputToStdOut;
447 | Act->MemoryProfile = MemoryProfile;
448 | Act->OutputInSafeMode = OutputInSafeMode;
449 | Act->IgnoreSystemInst = IgnoreSystemInst;
450 | Act->InteractiveDebug = InteractiveDebug;
451 | Act->BlackListFilename = BlackListFilename;
452 |
453 | Act->OutputFilename = TemplightAction::CreateOutputFilename(
454 | Clang, LocalOutputFilename, InstProfiler, OutputToStdOut, MemoryProfile);
455 |
456 | // Executing the templight action...
457 | bool Success = Clang->ExecuteAction(*Act);
458 | if (Clang->getFrontendOpts().DisableFree)
459 | BuryPointer(Act.release());
460 | return !Success;
461 | }
462 |
463 | static void ExecuteTemplightCommand(
464 | Driver &TheDriver, DiagnosticsEngine &Diags, Compilation &C, Command &J,
465 | const char *Argv0,
466 | SmallVector, 4> &FailingCommands) {
467 |
468 | // Since commandLineFitsWithinSystemLimits() may underestimate system's
469 | // capacity if the tool does not support response files, there is a chance/
470 | // that things will just work without a response file, so we silently just
471 | // skip it.
472 | if (J.getResponseFileSupport().ResponseKind !=
473 | ResponseFileSupport::RF_None &&
474 | !llvm::sys::commandLineFitsWithinSystemLimits(J.getExecutable(),
475 | J.getArguments()))
476 | {
477 | const std::string TmpName = TheDriver.GetTemporaryPath("response", "txt");
478 | J.setResponseFile(C.addTempFile(C.getArgs().MakeArgString(TmpName)));
479 | }
480 |
481 | if (StringRef(J.getCreator().getName()) == "clang") {
482 | // Initialize a compiler invocation object from the clang (-cc1) arguments.
483 | const ArgStringList &cc_arguments = J.getArguments();
484 |
485 | std::unique_ptr Clang(new CompilerInstance());
486 |
487 | int Res = !CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
488 | cc_arguments, Diags);
489 | if (Res)
490 | FailingCommands.push_back(std::make_pair(Res, &J));
491 |
492 | Clang->getFrontendOpts().DisableFree = false;
493 |
494 | // Infer the builtin include path if unspecified.
495 | void *GetExecutablePathVP = (void *)(intptr_t)GetExecutablePath;
496 | if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
497 | Clang->getHeaderSearchOpts().ResourceDir.empty())
498 | Clang->getHeaderSearchOpts().ResourceDir =
499 | CompilerInvocation::GetResourcesPath(Argv0, GetExecutablePathVP);
500 |
501 | // Create the compilers actual diagnostics engine.
502 | Clang->createDiagnostics(*llvm::vfs::getRealFileSystem());
503 | if (!Clang->hasDiagnostics()) {
504 | FailingCommands.push_back(std::make_pair(1, &J));
505 | return;
506 | }
507 |
508 | LocalOutputFilename =
509 | ""; // Let the filename be created from options or output file name.
510 | std::string TemplightOutFile = TemplightAction::CreateOutputFilename(
511 | Clang.get(), "", InstProfiler, OutputToStdOut, MemoryProfile);
512 | // Check if templight filename is in a temporary path:
513 | if (Clang->getFrontendOpts().UseTemporary) {
514 | C.addTempFile(TemplightOutFile.c_str());
515 | TempOutputFiles.push_back(TemplightOutFile);
516 | }
517 |
518 | // Execute the frontend actions.
519 | Res = ExecuteTemplightInvocation(Clang.get());
520 | if (Res)
521 | FailingCommands.push_back(std::make_pair(Res, &J));
522 |
523 | } else {
524 |
525 | const Command *FailingCommand = nullptr;
526 | if (int Res = C.ExecuteCommand(J, FailingCommand))
527 | FailingCommands.push_back(std::make_pair(Res, FailingCommand));
528 | }
529 | }
530 |
531 | int main(int argc_, const char **argv_) {
532 | llvm::InitLLVM X(argc_, argv_);
533 |
534 | if (llvm::sys::Process::FixupStandardFileDescriptors())
535 | return 1;
536 |
537 | SmallVector Args(argv_, argv_ + argc_);
538 |
539 | auto TargetAndMode = getTargetAndModeFromProgramName(Args[0]);
540 |
541 | llvm::BumpPtrAllocator A;
542 | llvm::StringSaver Saver(A);
543 |
544 | // Parse response files using the GNU syntax, unless we're in CL mode. There
545 | // are two ways to put clang in CL compatibility mode: Args[0] is either
546 | // clang-cl or cl, or --driver-mode=cl is on the command line. The normal
547 | // command line parsing can't happen until after response file parsing, so we
548 | // have to manually search for a --driver-mode=cl argument the hard way.
549 | // Finally, our -cc1 tools don't care which tokenization mode we use because
550 | // response files written by clang will tokenize the same way in either mode.
551 | bool ClangCLMode = llvm::StringRef(TargetAndMode.DriverMode).ends_with("cl");
552 |
553 | enum { Default, POSIX, Windows } RSPQuoting = Default;
554 | for (const char *F : Args) {
555 | if (strcmp(F, "--rsp-quoting=posix") == 0)
556 | RSPQuoting = POSIX;
557 | else if (strcmp(F, "--rsp-quoting=windows") == 0)
558 | RSPQuoting = Windows;
559 | }
560 |
561 | bool MarkEOLs = ClangCLMode;
562 |
563 | llvm::cl::TokenizerCallback Tokenizer;
564 | if (RSPQuoting == Windows || (RSPQuoting == Default && ClangCLMode))
565 | Tokenizer = &llvm::cl::TokenizeWindowsCommandLine;
566 | else
567 | Tokenizer = &llvm::cl::TokenizeGNUCommandLine;
568 |
569 | // Determines whether we want nullptr markers in Args to indicate response
570 | // files end-of-lines. We only use this for the /LINK driver argument.
571 | if (MarkEOLs && Args.size() > 1 && StringRef(Args[1]).starts_with("-cc1"))
572 | MarkEOLs = false;
573 | llvm::cl::ExpansionContext ECtx(A, Tokenizer);
574 | ECtx.setMarkEOLs(MarkEOLs);
575 | if (llvm::Error Err = ECtx.expandResponseFiles(Args)) {
576 | llvm::errs() << toString(std::move(Err)) << '\n';
577 | return 1;
578 | }
579 |
580 | // Handle CL and _CL_ which permits additional command line options to be
581 | // prepended or appended.
582 | if (ClangCLMode) {
583 | // Arguments in "CL" are prepended.
584 | std::optional OptCL = llvm::sys::Process::GetEnv("CL");
585 | if (OptCL) {
586 | SmallVector PrependedOpts;
587 | getCLEnvVarOptions(*OptCL, Saver, PrependedOpts);
588 |
589 | // Insert right after the program name to prepend to the argument list.
590 | Args.insert(Args.begin() + 1, PrependedOpts.begin(), PrependedOpts.end());
591 | }
592 | // Arguments in "_CL_" are appended.
593 | std::optional Opt_CL_ = llvm::sys::Process::GetEnv("_CL_");
594 | if (Opt_CL_) {
595 | SmallVector AppendedOpts;
596 | getCLEnvVarOptions(*Opt_CL_, Saver, AppendedOpts);
597 |
598 | // Insert at the end of the argument list to append.
599 | Args.append(AppendedOpts.begin(), AppendedOpts.end());
600 | }
601 | }
602 |
603 | llvm::StringSet<> SavedStrings;
604 | // Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the
605 | // scenes.
606 | if (const char *OverrideStr = ::getenv("CCC_OVERRIDE_OPTIONS")) {
607 | // FIXME: Driver shouldn't take extra initial argument.
608 | clang::driver::applyOverrideOptions(Args, OverrideStr, SavedStrings, &llvm::errs());
609 | }
610 |
611 | // Separate out templight and clang flags. templight flags are "-Xtemplight
612 | // "
613 | SmallVector TemplightArgs, ClangArgs;
614 | TemplightArgs.push_back(Args[0]);
615 | ClangArgs.push_back(Args[0]);
616 | for (int i = 1, size = Args.size(); i < size; /* in loop */) {
617 | if ((Args[i] != nullptr) && (strcmp(Args[i], "-Xtemplight") == 0)) {
618 | while (i < size - 1 && Args[++i] == nullptr) /* skip EOLs */
619 | ;
620 | TemplightArgs.push_back(Args[i]); // the word after -Xtemplight
621 | if (i == size - 1) // was this the last argument?
622 | break;
623 | while (i < size - 1 && Args[++i] == nullptr) /* skip EOLs */
624 | ;
625 | } else {
626 | if ((Args[i] != nullptr) && ((strcmp(Args[i], "-help") == 0) ||
627 | (strcmp(Args[i], "--help") == 0))) {
628 | // Print the help for the templight options:
629 | PrintTemplightHelp();
630 | }
631 | ClangArgs.push_back(
632 | Args[i++]); // also leave -help to driver (to print its help info too)
633 | }
634 | }
635 |
636 | cl::ParseCommandLineOptions(
637 | TemplightArgs.size(), &TemplightArgs[0],
638 | "A tool to profile template instantiations in C++ code.\n");
639 |
640 | bool CanonicalPrefixes = true;
641 | for (int i = 1, size = ClangArgs.size(); i < size; ++i) {
642 | // Skip end-of-line response file markers
643 | if (ClangArgs[i] == nullptr)
644 | continue;
645 | if (StringRef(ClangArgs[i]) == "-canonical-prefixes")
646 | CanonicalPrefixes = true;
647 | else if (StringRef(ClangArgs[i]) == "-no-canonical-prefixes")
648 | CanonicalPrefixes = false;
649 | }
650 |
651 | std::string Path = GetExecutablePath(ClangArgs[0], CanonicalPrefixes);
652 |
653 | IntrusiveRefCntPtr DiagOpts =
654 | CreateAndPopulateDiagOpts(ClangArgs);
655 |
656 | TextDiagnosticPrinter *DiagClient =
657 | new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
658 | FixupDiagPrefixExeName(DiagClient, Path);
659 |
660 | IntrusiveRefCntPtr DiagID(new DiagnosticIDs());
661 |
662 | DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
663 |
664 | if (!DiagOpts->DiagnosticSerializationFile.empty()) {
665 | auto SerializedConsumer =
666 | clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile,
667 | &*DiagOpts, /*MergeChildRecords=*/true);
668 | Diags.setClient(new ChainedDiagnosticConsumer(
669 | Diags.takeClient(), std::move(SerializedConsumer)));
670 | }
671 |
672 | ProcessWarningOptions(Diags, *DiagOpts, *llvm::vfs::getRealFileSystem(), /*ReportDiags=*/false);
673 |
674 | // Prepare a variable for the return value:
675 | int Res = 0;
676 |
677 | llvm::InitializeAllTargets();
678 | llvm::InitializeAllTargetMCs();
679 | llvm::InitializeAllAsmPrinters();
680 | llvm::InitializeAllAsmParsers();
681 |
682 | // Handle -cc1 integrated tools, even if -cc1 was expanded from a response
683 | // file.
684 | auto FirstArg = std::find_if(ClangArgs.begin() + 1, ClangArgs.end(),
685 | [](const char *A) { return A != nullptr; });
686 | bool invokeCC1 =
687 | (FirstArg != ClangArgs.end() && StringRef(*FirstArg).starts_with("-cc1"));
688 | if (invokeCC1) {
689 | // If -cc1 came from a response file, remove the EOL sentinels.
690 | if (MarkEOLs) {
691 | auto newEnd = std::remove(ClangArgs.begin(), ClangArgs.end(), nullptr);
692 | ClangArgs.resize(newEnd - ClangArgs.begin());
693 | }
694 |
695 | std::unique_ptr Clang(new CompilerInstance());
696 |
697 | Res = !CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
698 | ArrayRef(ClangArgs.data() + 2, ClangArgs.data() + ClangArgs.size()),
699 | Diags);
700 |
701 | // Infer the builtin include path if unspecified.
702 | void *GetExecutablePathVP = (void *)(intptr_t)GetExecutablePath;
703 | if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
704 | Clang->getHeaderSearchOpts().ResourceDir.empty())
705 | Clang->getHeaderSearchOpts().ResourceDir =
706 | CompilerInvocation::GetResourcesPath(ClangArgs[0],
707 | GetExecutablePathVP);
708 |
709 | // Create the compilers actual diagnostics engine.
710 | Clang->createDiagnostics(*llvm::vfs::getRealFileSystem());
711 | if (!Clang->hasDiagnostics()) {
712 | return 1;
713 | }
714 |
715 | LocalOutputFilename = OutputFilename;
716 |
717 | // Execute the frontend actions.
718 | Res = ExecuteTemplightInvocation(Clang.get());
719 |
720 | // When running with -disable-free, don't do any destruction or shutdown.
721 | if (Clang->getFrontendOpts().DisableFree) {
722 | if (llvm::AreStatisticsEnabled() || Clang->getFrontendOpts().ShowStats)
723 | llvm::PrintStatistics();
724 | BuryPointer(std::move(Clang));
725 | }
726 |
727 | } else {
728 |
729 | Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
730 | TheDriver.setTitle("templight");
731 |
732 | TheDriver.setTargetAndMode(TargetAndMode);
733 | insertTargetAndModeArgs(TargetAndMode, ClangArgs, SavedStrings);
734 |
735 | if (!SetBackdoorDriverOutputsFromEnvVars(TheDriver)) {
736 | return 1;
737 | }
738 |
739 | std::unique_ptr C(TheDriver.BuildCompilation(ClangArgs));
740 | if (!C.get()) {
741 | return 1;
742 | }
743 |
744 | // If there were errors building the compilation, quit now.
745 | if (TheDriver.getDiags().hasErrorOccurred())
746 | return 1;
747 |
748 | SmallVector, 4> FailingCommands;
749 | for (auto &J : C->getJobs())
750 | ExecuteTemplightCommand(TheDriver, Diags, *C, J, ClangArgs[0],
751 | FailingCommands);
752 |
753 | // Merge all the temp files into a single output file:
754 | if (!TempOutputFiles.empty()) {
755 | if (OutputFilename.empty())
756 | OutputFilename = "a";
757 | std::string FinalOutputFilename = TemplightAction::CreateOutputFilename(
758 | nullptr, OutputFilename, InstProfiler, OutputToStdOut, MemoryProfile);
759 | if ((!FinalOutputFilename.empty()) && (FinalOutputFilename != "-")) {
760 | std::error_code error;
761 | llvm::raw_fd_ostream TraceOS(FinalOutputFilename, error,
762 | llvm::sys::fs::OF_None);
763 | if (error) {
764 | llvm::errs() << "Error: [Templight] Can not open file to write trace "
765 | "of template instantiations: "
766 | << FinalOutputFilename << " Error: " << error.message();
767 | } else {
768 | for (SmallVector::iterator
769 | it = TempOutputFiles.begin(),
770 | it_end = TempOutputFiles.end();
771 | it != it_end; ++it) {
772 | llvm::ErrorOr> file_epbuf =
773 | llvm::MemoryBuffer::getFile(llvm::Twine(*it));
774 | if (file_epbuf && file_epbuf.get()) {
775 | TraceOS << StringRef(file_epbuf.get()->getBufferStart(),
776 | file_epbuf.get()->getBufferEnd() -
777 | file_epbuf.get()->getBufferStart())
778 | << '\n';
779 | }
780 | }
781 | }
782 | }
783 | }
784 |
785 | // Remove temp files.
786 | C->CleanupFileList(C->getTempFiles());
787 |
788 | // If the command succeeded, the number of failing commands should zero:
789 | Res = FailingCommands.size();
790 |
791 | // Otherwise, remove result files and print extra information about abnormal
792 | // failures.
793 | for (SmallVectorImpl>::iterator
794 | it = FailingCommands.begin(),
795 | ie = FailingCommands.end();
796 | it != ie; ++it) {
797 | int FailRes = it->first;
798 | const Command *FailingCommand = it->second;
799 |
800 | // Remove result files if we're not saving temps.
801 | if (!C->getArgs().hasArg(options::OPT_save_temps)) {
802 | const JobAction *JA = cast(&FailingCommand->getSource());
803 | C->CleanupFileMap(C->getResultFiles(), JA, true);
804 |
805 | // Failure result files are valid unless we crashed.
806 | if (FailRes < 0)
807 | C->CleanupFileMap(C->getFailureResultFiles(), JA, true);
808 | }
809 |
810 | // Print extra information about abnormal failures, if possible.
811 | const Tool &FailingTool = FailingCommand->getCreator();
812 |
813 | if (!FailingCommand->getCreator().hasGoodDiagnostics() || FailRes != 1) {
814 | if (FailRes < 0)
815 | Diags.Report(clang::diag::err_drv_command_signalled)
816 | << FailingTool.getShortName();
817 | else
818 | Diags.Report(clang::diag::err_drv_command_failed)
819 | << FailingTool.getShortName() << FailRes;
820 | }
821 | }
822 | }
823 |
824 | // If any timers were active but haven't been destroyed yet, print their
825 | // results now. This happens in -disable-free mode.
826 | llvm::TimerGroup::printAll(llvm::errs());
827 |
828 | #ifdef LLVM_ON_WIN32
829 | // Exit status should not be negative on Win32, unless abnormal termination.
830 | // Once abnormal termiation was caught, negative status should not be
831 | // propagated.
832 | if (Res < 0)
833 | Res = 1;
834 | #endif
835 |
836 | // If we have multiple failing commands, we return the result of the first
837 | // failing command.
838 | return Res;
839 | }
840 |
--------------------------------------------------------------------------------
/templight_messages.proto:
--------------------------------------------------------------------------------
1 | message TemplightHeader {
2 | required uint32 version = 1;
3 | optional string source_file = 2;
4 | }
5 |
6 | message TemplightEntry {
7 | enum SynthesisKind {
8 | TemplateInstantiation = 0;
9 | DefaultTemplateArgumentInstantiation = 1;
10 | DefaultFunctionArgumentInstantiation = 2;
11 | ExplicitTemplateArgumentSubstitution = 3;
12 | DeducedTemplateArgumentSubstitution = 4;
13 | PriorTemplateArgumentSubstitution = 5;
14 | DefaultTemplateArgumentChecking = 6;
15 | ExceptionSpecEvaluation = 7;
16 | ExceptionSpecInstantiation = 8;
17 | DeclaringSpecialMember = 9;
18 | DefiningSynthesizedFunction = 10;
19 | Memoization = 11;
20 | }
21 |
22 | message TemplateName {
23 | // oneof rep {
24 | // string name = 1;
25 | // bytes compressed_name = 2;
26 | // }
27 | optional string name = 1;
28 | optional bytes compressed_name = 2;
29 | optional uint32 dict_id = 3;
30 | }
31 |
32 | message SourceLocation {
33 | optional string file_name = 1;
34 | required uint32 file_id = 2;
35 | required uint32 line = 3;
36 | optional uint32 column = 4;
37 | }
38 |
39 | message Begin {
40 | required SynthesisKind kind = 1;
41 | required TemplateName name = 2;
42 | required SourceLocation location = 3;
43 | optional double time_stamp = 4;
44 | optional uint64 memory_usage = 5;
45 | optional SourceLocation template_origin = 6;
46 | }
47 |
48 | message End {
49 | optional double time_stamp = 1;
50 | optional uint64 memory_usage = 2;
51 | }
52 |
53 | // oneof begin_or_end {
54 | // Begin begin = 1;
55 | // End end = 2;
56 | // }
57 | optional Begin begin = 1;
58 | optional End end = 2;
59 | }
60 |
61 | message DictionaryEntry {
62 | required string marked_name = 1;
63 | repeated uint32 marker_ids = 2;
64 | }
65 |
66 | message TemplightTrace {
67 | required TemplightHeader header = 1;
68 | repeated TemplightEntry entries = 2;
69 | repeated DictionaryEntry names = 3;
70 | }
71 |
72 | message TemplightTraceCollection {
73 | repeated TemplightTrace traces = 1;
74 | }
75 |
--------------------------------------------------------------------------------
/templight_symlink.cmake:
--------------------------------------------------------------------------------
1 | # We need to execute this script at installation time because the
2 | # DESTDIR environment variable may be unset at configuration time.
3 | # See PR8397.
4 |
5 | if(UNIX)
6 | set(CLANGXX_LINK_OR_COPY create_symlink)
7 | set(CLANGXX_DESTDIR $ENV{DESTDIR})
8 | else()
9 | set(CLANGXX_LINK_OR_COPY copy)
10 | endif()
11 |
12 | # CMAKE_EXECUTABLE_SUFFIX is undefined on cmake scripts. See PR9286.
13 | if( WIN32 )
14 | set(EXECUTABLE_SUFFIX ".exe")
15 | else()
16 | set(EXECUTABLE_SUFFIX "")
17 | endif()
18 |
19 | set(bindir "${CLANGXX_DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/")
20 | set(templight "templight${EXECUTABLE_SUFFIX}")
21 | set(templightxx "templight++${EXECUTABLE_SUFFIX}")
22 | set(templight_cl "templight-cl${EXECUTABLE_SUFFIX}")
23 |
24 | message("Creating templight++ executable based on ${templight}")
25 |
26 | execute_process(
27 | COMMAND "${CMAKE_COMMAND}" -E ${CLANGXX_LINK_OR_COPY} "${templight}" "${templightxx}"
28 | WORKING_DIRECTORY "${bindir}")
29 |
30 | message("Creating templight-cl executable based on ${templight}")
31 |
32 | execute_process(
33 | COMMAND "${CMAKE_COMMAND}" -E ${CLANGXX_LINK_OR_COPY} "${templight}" "${templight_cl}"
34 | WORKING_DIRECTORY "${bindir}")
35 |
--------------------------------------------------------------------------------
/test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Test runner infrastructure for Templight. This configures the Clang
2 | # test trees for use by Lit, and delegates to LLVM's lit test handlers.
3 |
4 | set(TEMPLIGHT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
5 | set(TEMPLIGHT_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/..")
6 |
7 | if (CMAKE_CFG_INTDIR STREQUAL ".")
8 | set(LLVM_BUILD_MODE ".")
9 | else ()
10 | set(LLVM_BUILD_MODE "%(build_mode)s")
11 | endif ()
12 |
13 | string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} TEMPLIGHT_DIR ${LLVM_RUNTIME_OUTPUT_INTDIR})
14 |
15 | set(TEMPLIGHT_TEST_DEPS
16 | ${CLANG_TEST_DEPS}
17 | TemplightUnitTests
18 | templight
19 | llvm-config
20 | FileCheck
21 | count
22 | not
23 | )
24 |
25 | set(TEMPLIGHT_TEST_EXTRA_ARGS "")
26 |
27 | configure_lit_site_cfg(
28 | ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
29 | ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
30 | )
31 |
32 | configure_lit_site_cfg(
33 | ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in
34 | ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py
35 | MAIN_CONFIG
36 | ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.cfg.py
37 | )
38 |
39 | add_lit_testsuite(check-templight "Running Templight regression tests"
40 | ${CMAKE_CURRENT_BINARY_DIR}
41 | DEPENDS ${TEMPLIGHT_TEST_DEPS}
42 | ARGS ${TEMPLIGHT_TEST_EXTRA_ARGS}
43 | )
44 |
45 | set_target_properties(check-templight PROPERTIES FOLDER "Templight tests")
46 |
--------------------------------------------------------------------------------
/test/Unit/lit.cfg.py:
--------------------------------------------------------------------------------
1 | # -*- Python -*-
2 |
3 | # Configuration file for the 'lit' test runner.
4 |
5 | import os
6 | import platform
7 | import subprocess
8 |
9 | import lit.formats
10 | import lit.util
11 |
12 | # name: The name of this test suite.
13 | config.name = 'Templight-Unit'
14 |
15 | # suffixes: A list of file extensions to treat as test files.
16 | config.suffixes = []
17 |
18 | # test_source_root: The root path where tests are located.
19 | # test_exec_root: The root path where tests should be run.
20 | config.test_exec_root = os.path.join(config.templight_obj_root, 'unittests')
21 | config.test_source_root = config.test_exec_root
22 |
23 | # testFormat: The test format to use to interpret tests.
24 | config.test_format = lit.formats.GoogleTest('.', 'Tests')
25 |
--------------------------------------------------------------------------------
/test/Unit/lit.site.cfg.py.in:
--------------------------------------------------------------------------------
1 | @LIT_SITE_CFG_IN_HEADER@
2 |
3 | import sys
4 |
5 | config.llvm_src_root = "@LLVM_SOURCE_DIR@"
6 | config.llvm_obj_root = "@LLVM_BINARY_DIR@"
7 | config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
8 | config.llvm_libs_dir = "@LLVM_LIBS_DIR@"
9 | config.llvm_build_mode = "@LLVM_BUILD_MODE@"
10 | config.clang_obj_root = "@CLANG_BINARY_DIR@"
11 | config.enable_shared = @ENABLE_SHARED@
12 | config.shlibdir = "@SHLIBDIR@"
13 | config.target_triple = "@TARGET_TRIPLE@"
14 |
15 | config.templight_obj_root = "@TEMPLIGHT_BINARY_DIR@"
16 | config.templight_src_root = "@TEMPLIGHT_SOURCE_DIR@"
17 |
18 | # Support substitution of the tools_dir, libs_dirs, and build_mode with user
19 | # parameters. This is used when we can't determine the tool dir at
20 | # configuration time.
21 | try:
22 | config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
23 | config.llvm_libs_dir = config.llvm_libs_dir % lit_config.params
24 | config.llvm_build_mode = config.llvm_build_mode % lit_config.params
25 | except KeyError:
26 | e = sys.exc_info()[1]
27 | key, = e.args
28 | lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
29 |
30 | # Let the main config do the real work.
31 | lit_config.load_config(config, "@TEMPLIGHT_SOURCE_DIR@/test/Unit/lit.cfg.py")
32 |
--------------------------------------------------------------------------------
/test/lit.cfg:
--------------------------------------------------------------------------------
1 | # -*- Python -*-
2 |
3 | import os
4 | import platform
5 | import re
6 | import subprocess
7 | import tempfile
8 |
9 | import lit.formats
10 | import lit.util
11 |
12 | from lit.llvm import llvm_config# Configuration file for the 'lit' test runner.
13 |
14 | # name: The name of this test suite.
15 | config.name = 'Templight'
16 |
17 | # suffixes: A list of file extensions to treat as test files.
18 | config.suffixes = ['.c', '.cpp', '.cppm', '.m', '.mm', '.cu',
19 | '.ll', '.cl', '.s', '.S', '.modulemap', '.test', '.rs']
20 |
21 | # excludes: A list of directories to exclude from the testsuite. The 'Inputs'
22 | # subdirectories contain auxiliary inputs for various tests in their parent
23 | # directories.
24 | config.excludes = ['Inputs', 'CMakeLists.txt']
25 |
26 | # test_source_root: The root path where tests are located.
27 | config.test_source_root = os.path.dirname(__file__)
28 |
29 | config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell)
30 |
31 | # test_exec_root: The root path where tests should be run.
32 | config.test_exec_root = os.path.join(config.templight_obj_root, 'test')
33 |
34 | llvm_config.use_default_substitutions()
35 |
36 | llvm_config.use_clang()
37 |
38 | config.substitutions.append(('%PATH%', config.environment['PATH']))
39 |
40 | config.substitutions.append(('%templight_cc1', 'templight -cc1'))
41 |
--------------------------------------------------------------------------------
/test/lit.site.cfg.in:
--------------------------------------------------------------------------------
1 | @LIT_SITE_CFG_IN_HEADER@
2 |
3 | import sys
4 |
5 | config.llvm_src_root = "@LLVM_SOURCE_DIR@"
6 | config.llvm_obj_root = "@LLVM_BINARY_DIR@"
7 | config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
8 | config.llvm_libs_dir = "@LLVM_LIBS_DIR@"
9 | config.llvm_shlib_dir = "@SHLIBDIR@"
10 | config.llvm_plugin_ext = "@LLVM_PLUGIN_EXT@"
11 |
12 | config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
13 |
14 | config.clang_obj_root = "@CLANG_BINARY_DIR@"
15 | config.clang_src_dir = "@CLANG_SOURCE_DIR@"
16 | config.clang_tools_dir = "@CLANG_TOOLS_DIR@"
17 |
18 | config.templight_obj_root = "@TEMPLIGHT_BINARY_DIR@"
19 | config.templight_src_root = "@TEMPLIGHT_SOURCE_DIR@"
20 |
21 | config.host_triple = "@LLVM_HOST_TRIPLE@"
22 | config.target_triple = "@LLVM_TARGET_TRIPLE@"
23 | config.host_cxx = "@CMAKE_CXX_COMPILER@"
24 | config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@"
25 | config.clang_default_cxx_stdlib = "@CLANG_DEFAULT_CXX_STDLIB@"
26 | config.host_arch = "@HOST_ARCH@"
27 | config.python_executable = "@PYTHON_EXECUTABLE@"
28 | config.use_z3_solver = lit_config.params.get('USE_Z3_SOLVER', "@USE_Z3_SOLVER@")
29 |
30 | # Support substitution of the tools and libs dirs with user parameters. This is
31 | # used when we can't determine the tool dir at configuration time.
32 | try:
33 | config.clang_tools_dir = config.clang_tools_dir % lit_config.params
34 | config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
35 | config.llvm_shlib_dir = config.llvm_shlib_dir % lit_config.params
36 | config.llvm_libs_dir = config.llvm_libs_dir % lit_config.params
37 | except KeyError:
38 | e = sys.exc_info()[1]
39 | key, = e.args
40 | lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
41 |
42 | import lit.llvm
43 | lit.llvm.initialize(lit_config, config)
44 |
45 | # Let the main config do the real work.
46 | lit_config.load_config(config, "@TEMPLIGHT_SOURCE_DIR@/test/lit.cfg")
47 |
--------------------------------------------------------------------------------
/test/templight-driver-flag.cpp:
--------------------------------------------------------------------------------
1 | // RUN: rm -f %t.trace.pbf
2 |
3 | // RUN: %templight_cc1 %s -Xtemplight -profiler \
4 | // RUN: -Xtemplight -output=%t.trace.pbf
5 |
6 | // grep the filename in the output trace file. That shouldn't be mangled.
7 | // RUN: grep "%s" %t.trace.pbf
8 |
--------------------------------------------------------------------------------
/test/templight_as_compiler.cpp:
--------------------------------------------------------------------------------
1 | // RUN: templight++ %s
2 |
3 | int main() {
4 | int i = 10;
5 | (void)i;
6 | }
7 |
--------------------------------------------------------------------------------
/unittests/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_custom_target(TemplightUnitTests)
2 | set_target_properties(TemplightUnitTests PROPERTIES FOLDER "Templight Unit Tests")
3 |
4 | function(add_templight_unittest test_dirname)
5 | add_unittest(TemplightUnitTests ${test_dirname} ${ARGN})
6 | endfunction()
7 |
8 | set(LLVM_LINK_COMPONENTS
9 | Support
10 | )
11 |
12 | add_templight_unittest(TemplightTests
13 | TemplightActionTest.cpp
14 | )
15 |
16 | target_link_libraries(TemplightTests
17 | PRIVATE
18 | clangBasic
19 | clangFrontend
20 | clangSerialization
21 | clangTemplight
22 | clangTooling
23 | )
24 |
--------------------------------------------------------------------------------
/unittests/TemplightActionTest.cpp:
--------------------------------------------------------------------------------
1 | //===- TemplightActionTest.cpp ---------------------*- C++ -*--------------===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #include "TemplightAction.h"
11 | #include "clang/Frontend/CompilerInstance.h"
12 | #include "clang/Frontend/FrontendActions.h"
13 | #include "clang/Tooling/Tooling.h"
14 | #include "llvm/ADT/StringRef.h"
15 | #include "gtest/gtest.h"
16 |
17 | using namespace clang;
18 |
19 | TEST(TemplightActionTest, SimpleInvocation) {
20 | EXPECT_TRUE(
21 | tooling::runToolOnCode(std::make_unique(
22 | std::make_unique()),
23 | "void f() {;}"));
24 | }
25 |
--------------------------------------------------------------------------------
/utils/ExtraWriters/TemplightExtraWriters.cpp:
--------------------------------------------------------------------------------
1 | //===- TemplightExtraWriters.cpp ----------------*- C++ -*-----------------===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #include "TemplightExtraWriters.h"
11 |
12 | #include
13 |
14 | #include
15 | #include
16 | #include
17 |
18 | namespace clang {
19 |
20 | static const char *const SynthesisKindStrings[] = {
21 | "TemplateInstantiation",
22 | "DefaultTemplateArgumentInstantiation",
23 | "DefaultFunctionArgumentInstantiation",
24 | "ExplicitTemplateArgumentSubstitution",
25 | "DeducedTemplateArgumentSubstitution",
26 | "PriorTemplateArgumentSubstitution",
27 | "DefaultTemplateArgumentChecking",
28 | "ExceptionSpecInstantiation",
29 | "DeclaringSpecialMember",
30 | "DefiningSynthesizedFunction",
31 | "Memoization"};
32 |
33 | static std::string escapeXml(const std::string &Input) {
34 | std::string Result;
35 | Result.reserve(64);
36 |
37 | unsigned i, pos = 0;
38 | for (i = 0; i < Input.length(); ++i) {
39 | if (Input[i] == '<' || Input[i] == '>' || Input[i] == '"' ||
40 | Input[i] == '\'' || Input[i] == '&') {
41 | Result.insert(Result.length(), Input, pos, i - pos);
42 | pos = i + 1;
43 | switch (Input[i]) {
44 | case '<':
45 | Result += "<";
46 | break;
47 | case '>':
48 | Result += ">";
49 | break;
50 | case '\'':
51 | Result += "'";
52 | break;
53 | case '"':
54 | Result += """;
55 | break;
56 | case '&':
57 | Result += "&";
58 | break;
59 | default:
60 | break;
61 | }
62 | }
63 | }
64 | Result.insert(Result.length(), Input, pos, i - pos);
65 | return Result;
66 | }
67 |
68 | } // namespace clang
69 | namespace llvm {
70 | namespace yaml {
71 |
72 | template <>
73 | struct ScalarEnumerationTraits<
74 | clang::Sema::CodeSynthesisContext::SynthesisKind> {
75 | static void
76 | enumeration(IO &io, clang::Sema::CodeSynthesisContext::SynthesisKind &value) {
77 |
78 | #define def_enum_case(e) io.enumCase(value, SynthesisKindStrings[e], e)
79 |
80 | using namespace clang;
81 | def_enum_case(CodeSynthesisContext::TemplateInstantiation);
82 | def_enum_case(CodeSynthesisContext::DefaultTemplateArgumentInstantiation);
83 | def_enum_case(CodeSynthesisContext::DefaultFunctionArgumentInstantiation);
84 | def_enum_case(CodeSynthesisContext::ExplicitTemplateArgumentSubstitution);
85 | def_enum_case(CodeSynthesisContext::DeducedTemplateArgumentSubstitution);
86 | def_enum_case(CodeSynthesisContext::PriorTemplateArgumentSubstitution);
87 | def_enum_case(CodeSynthesisContext::DefaultTemplateArgumentChecking);
88 | def_enum_case(CodeSynthesisContext::ExceptionSpecInstantiation);
89 | def_enum_case(CodeSynthesisContext::DeclaringSpecialMember);
90 | def_enum_case(CodeSynthesisContext::DefiningSynthesizedFunction);
91 | def_enum_case(CodeSynthesisContext::Memoization);
92 |
93 | #undef def_enum_case
94 | }
95 | };
96 |
97 | template <> struct MappingTraits {
98 | static void mapping(IO &io, clang::PrintableTemplightEntryBegin &Entry) {
99 | bool b = true;
100 | io.mapRequired("IsBegin", b);
101 | // must be converted to string before, due to some BS with yaml traits.
102 | std::string kind = clang::SynthesisKindStrings[Entry.SynthesisKind];
103 | io.mapRequired("Kind", kind);
104 | io.mapOptional("Name", Entry.Name);
105 | std::string loc = Entry.FileName + "|" + std::to_string(Entry.Line) + "|" +
106 | std::to_string(Entry.Column);
107 | io.mapOptional("Location", loc);
108 | io.mapRequired("TimeStamp", Entry.TimeStamp);
109 | io.mapOptional("MemoryUsage", Entry.MemoryUsage);
110 | std::string ori = Entry.TempOri_FileName + "|" +
111 | std::to_string(Entry.TempOri_Line) + "|" +
112 | std::to_string(Entry.TempOri_Column);
113 | io.mapOptional("TemplateOrigin", ori);
114 | }
115 | };
116 |
117 | template <> struct MappingTraits {
118 | static void mapping(IO &io, clang::PrintableTemplightEntryEnd &Entry) {
119 | bool b = false;
120 | io.mapRequired("IsBegin", b);
121 | io.mapRequired("TimeStamp", Entry.TimeStamp);
122 | io.mapOptional("MemoryUsage", Entry.MemoryUsage);
123 | }
124 | };
125 |
126 | } // namespace yaml
127 | } // namespace llvm
128 | namespace clang {
129 |
130 | void TemplightYamlWriter::initialize(const std::string &aSourceName) {
131 | Output->beginSequence();
132 | }
133 |
134 | void TemplightYamlWriter::finalize() { Output->endSequence(); }
135 |
136 | void TemplightYamlWriter::printEntry(
137 | const PrintableTemplightEntryBegin &Entry) {
138 | void *SaveInfo;
139 | if (Output->preflightElement(1, SaveInfo)) {
140 | llvm::yaml::EmptyContext Context;
141 | llvm::yaml::yamlize(*Output,
142 | const_cast(Entry), true,
143 | Context);
144 | Output->postflightElement(SaveInfo);
145 | }
146 | }
147 |
148 | void TemplightYamlWriter::printEntry(const PrintableTemplightEntryEnd &Entry) {
149 | void *SaveInfo;
150 | if (Output->preflightElement(1, SaveInfo)) {
151 | llvm::yaml::EmptyContext Context;
152 | llvm::yaml::yamlize(*Output,
153 | const_cast(Entry), true,
154 | Context);
155 | Output->postflightElement(SaveInfo);
156 | }
157 | }
158 |
159 | TemplightYamlWriter::TemplightYamlWriter(llvm::raw_ostream &aOS)
160 | : TemplightWriter(aOS) {
161 | Output.reset(new llvm::yaml::Output(OutputOS));
162 | Output->beginDocuments();
163 | }
164 |
165 | TemplightYamlWriter::~TemplightYamlWriter() { Output->endDocuments(); }
166 |
167 | TemplightXmlWriter::TemplightXmlWriter(llvm::raw_ostream &aOS)
168 | : TemplightWriter(aOS) {
169 | OutputOS << "\n";
170 | }
171 |
172 | TemplightXmlWriter::~TemplightXmlWriter() {}
173 |
174 | void TemplightXmlWriter::initialize(const std::string &aSourceName) {
175 | OutputOS << "\n";
176 | }
177 |
178 | void TemplightXmlWriter::finalize() { OutputOS << "\n"; }
179 |
180 | void TemplightXmlWriter::printEntry(
181 | const PrintableTemplightEntryBegin &aEntry) {
182 | std::string EscapedName = escapeXml(aEntry.Name);
183 | OutputOS << llvm::format("\n"
184 | " %s\n"
185 | " \n"
186 | " %s|%d|%d\n",
187 | SynthesisKindStrings[aEntry.SynthesisKind],
188 | EscapedName.c_str(), aEntry.FileName.c_str(),
189 | aEntry.Line, aEntry.Column);
190 | OutputOS << llvm::format(" \n"
191 | " \n",
192 | aEntry.TimeStamp, aEntry.MemoryUsage);
193 | if (!aEntry.TempOri_FileName.empty()) {
194 | OutputOS << llvm::format(" %s|%d|%d\n",
195 | aEntry.TempOri_FileName.c_str(),
196 | aEntry.TempOri_Line, aEntry.TempOri_Column);
197 | }
198 | OutputOS << "\n";
199 | }
200 |
201 | void TemplightXmlWriter::printEntry(const PrintableTemplightEntryEnd &aEntry) {
202 | OutputOS << llvm::format("\n"
203 | " \n"
204 | " \n"
205 | "\n",
206 | aEntry.TimeStamp, aEntry.MemoryUsage);
207 | }
208 |
209 | TemplightTextWriter::TemplightTextWriter(llvm::raw_ostream &aOS)
210 | : TemplightWriter(aOS) {}
211 |
212 | TemplightTextWriter::~TemplightTextWriter() {}
213 |
214 | void TemplightTextWriter::initialize(const std::string &aSourceName) {
215 | OutputOS << " SourceFile = " << aSourceName << "\n";
216 | }
217 |
218 | void TemplightTextWriter::finalize() {}
219 |
220 | void TemplightTextWriter::printEntry(
221 | const PrintableTemplightEntryBegin &aEntry) {
222 | OutputOS << llvm::format("TemplateBegin\n"
223 | " Kind = %s\n"
224 | " Name = %s\n"
225 | " Location = %s|%d|%d\n",
226 | SynthesisKindStrings[aEntry.SynthesisKind],
227 | aEntry.Name.c_str(), aEntry.FileName.c_str(),
228 | aEntry.Line, aEntry.Column);
229 | OutputOS << llvm::format(" TimeStamp = %.9f\n"
230 | " MemoryUsage = %d\n",
231 | aEntry.TimeStamp, aEntry.MemoryUsage);
232 | if (!aEntry.TempOri_FileName.empty()) {
233 | OutputOS << llvm::format(" TemplateOrigin = %s|%d|%d\n",
234 | aEntry.TempOri_FileName.c_str(),
235 | aEntry.TempOri_Line, aEntry.TempOri_Column);
236 | }
237 | }
238 |
239 | void TemplightTextWriter::printEntry(const PrintableTemplightEntryEnd &aEntry) {
240 | OutputOS << llvm::format("TemplateEnd\n"
241 | " TimeStamp = %.9f\n"
242 | " MemoryUsage = %d\n",
243 | aEntry.TimeStamp, aEntry.MemoryUsage);
244 | }
245 |
246 | struct EntryTraversalTask {
247 | static const std::size_t invalid_id = ~std::size_t(0);
248 |
249 | PrintableTemplightEntryBegin start;
250 | PrintableTemplightEntryEnd finish;
251 | std::size_t nd_id, id_end, parent_id;
252 | EntryTraversalTask(const PrintableTemplightEntryBegin &aStart,
253 | std::size_t aNdId, std::size_t aParentId)
254 | : start(aStart), finish(), nd_id(aNdId), id_end(invalid_id),
255 | parent_id(aParentId){};
256 | };
257 |
258 | struct RecordedDFSEntryTree {
259 | static const std::size_t invalid_id = ~std::size_t(0);
260 |
261 | std::vector parent_stack;
262 | std::size_t cur_top;
263 |
264 | RecordedDFSEntryTree() : cur_top(invalid_id){};
265 |
266 | void beginEntry(const PrintableTemplightEntryBegin &aEntry) {
267 | parent_stack.push_back(
268 | EntryTraversalTask(aEntry, parent_stack.size(),
269 | (cur_top == invalid_id ? invalid_id : cur_top)));
270 | cur_top = parent_stack.size() - 1;
271 | };
272 |
273 | void endEntry(const PrintableTemplightEntryEnd &aEntry) {
274 | parent_stack[cur_top].finish = aEntry;
275 | parent_stack[cur_top].id_end = parent_stack.size();
276 | if (parent_stack[cur_top].parent_id == invalid_id)
277 | cur_top = invalid_id;
278 | else
279 | cur_top = parent_stack[cur_top].parent_id;
280 | };
281 | };
282 |
283 | TemplightTreeWriter::TemplightTreeWriter(llvm::raw_ostream &aOS)
284 | : TemplightWriter(aOS), p_tree(new RecordedDFSEntryTree()) {}
285 |
286 | TemplightTreeWriter::~TemplightTreeWriter() {}
287 |
288 | void TemplightTreeWriter::printEntry(
289 | const PrintableTemplightEntryBegin &aEntry) {
290 | p_tree->beginEntry(aEntry);
291 | }
292 |
293 | void TemplightTreeWriter::printEntry(const PrintableTemplightEntryEnd &aEntry) {
294 | p_tree->endEntry(aEntry);
295 | }
296 |
297 | void TemplightTreeWriter::initialize(const std::string &aSourceName) {
298 | this->initializeTree(aSourceName);
299 | }
300 |
301 | void TemplightTreeWriter::finalize() {
302 | std::vector open_set;
303 | std::vector &tree = p_tree->parent_stack;
304 |
305 | for (std::size_t i = 0, i_end = tree.size(); i != i_end; ++i) {
306 | while (!open_set.empty() && (i >= tree[open_set.back()].id_end)) {
307 | closePrintedTreeNode(tree[open_set.back()]);
308 | open_set.pop_back();
309 | }
310 | openPrintedTreeNode(tree[i]);
311 | open_set.push_back(i);
312 | }
313 | while (!open_set.empty()) {
314 | closePrintedTreeNode(tree[open_set.back()]);
315 | open_set.pop_back();
316 | }
317 |
318 | this->finalizeTree();
319 | }
320 |
321 | TemplightNestedXMLWriter::TemplightNestedXMLWriter(llvm::raw_ostream &aOS)
322 | : TemplightTreeWriter(aOS) {
323 | OutputOS << "\n";
324 | }
325 |
326 | TemplightNestedXMLWriter::~TemplightNestedXMLWriter() {}
327 |
328 | void TemplightNestedXMLWriter::initializeTree(const std::string &aSourceName) {
329 | OutputOS << "\n";
330 | }
331 |
332 | void TemplightNestedXMLWriter::finalizeTree() { OutputOS << "\n"; }
333 |
334 | void TemplightNestedXMLWriter::openPrintedTreeNode(
335 | const EntryTraversalTask &aNode) {
336 | const PrintableTemplightEntryBegin &BegEntry = aNode.start;
337 | const PrintableTemplightEntryEnd &EndEntry = aNode.finish;
338 | std::string EscapedName = escapeXml(BegEntry.Name);
339 |
340 | OutputOS << llvm::format("\n",
351 | EndEntry.TimeStamp - BegEntry.TimeStamp,
352 | EndEntry.MemoryUsage - BegEntry.MemoryUsage);
353 |
354 | // Print only first part (heading).
355 | }
356 |
357 | void TemplightNestedXMLWriter::closePrintedTreeNode(
358 | const EntryTraversalTask &aNode) {
359 | OutputOS << "\n";
360 | }
361 |
362 | TemplightGraphMLWriter::TemplightGraphMLWriter(llvm::raw_ostream &aOS)
363 | : TemplightTreeWriter(aOS), last_edge_id(0) {
364 | OutputOS << "\n"
365 | "\n";
369 | OutputOS << "\n"
371 | "\n"
373 | "\n"
375 | "\n"
377 | "0.0\n"
378 | "\n"
379 | "\n"
381 | "0\n"
382 | "\n"
383 | "\n";
385 | }
386 |
387 | TemplightGraphMLWriter::~TemplightGraphMLWriter() {
388 | OutputOS << "\n";
389 | }
390 |
391 | void TemplightGraphMLWriter::initializeTree(const std::string &aSourceName) {
392 | OutputOS << "\n";
393 | }
394 |
395 | void TemplightGraphMLWriter::finalizeTree() { OutputOS << "\n"; }
396 |
397 | void TemplightGraphMLWriter::openPrintedTreeNode(
398 | const EntryTraversalTask &aNode) {
399 | const PrintableTemplightEntryBegin &BegEntry = aNode.start;
400 | const PrintableTemplightEntryEnd &EndEntry = aNode.finish;
401 |
402 | OutputOS << llvm::format("\n", aNode.nd_id);
403 |
404 | std::string EscapedName = escapeXml(BegEntry.Name);
405 | OutputOS << llvm::format(" %s\n"
406 | " \"%s\"\n"
407 | " \"%s|%d|%d\"\n",
408 | SynthesisKindStrings[BegEntry.SynthesisKind],
409 | EscapedName.c_str(), BegEntry.FileName.c_str(),
410 | BegEntry.Line, BegEntry.Column);
411 | OutputOS << llvm::format(" %.9f\n"
412 | " %d\n",
413 | EndEntry.TimeStamp - BegEntry.TimeStamp,
414 | EndEntry.MemoryUsage - BegEntry.MemoryUsage);
415 | if (!BegEntry.TempOri_FileName.empty()) {
416 | OutputOS << llvm::format(" \"%s|%d|%d\"\n",
417 | BegEntry.TempOri_FileName.c_str(),
418 | BegEntry.TempOri_Line, BegEntry.TempOri_Column);
419 | }
420 |
421 | OutputOS << "\n";
422 | if (aNode.parent_id == RecordedDFSEntryTree::invalid_id)
423 | return;
424 |
425 | OutputOS << llvm::format("\n",
426 | last_edge_id++, aNode.parent_id, aNode.nd_id);
427 | }
428 |
429 | void TemplightGraphMLWriter::closePrintedTreeNode(
430 | const EntryTraversalTask &aNode) {}
431 |
432 | TemplightGraphVizWriter::TemplightGraphVizWriter(llvm::raw_ostream &aOS)
433 | : TemplightTreeWriter(aOS) {}
434 |
435 | TemplightGraphVizWriter::~TemplightGraphVizWriter() {}
436 |
437 | void TemplightGraphVizWriter::initializeTree(const std::string &aSourceName) {
438 | OutputOS << "digraph Trace {\n";
439 | }
440 |
441 | void TemplightGraphVizWriter::finalizeTree() { OutputOS << "}\n"; }
442 |
443 | void TemplightGraphVizWriter::openPrintedTreeNode(
444 | const EntryTraversalTask &aNode) {
445 | const PrintableTemplightEntryBegin &BegEntry = aNode.start;
446 | const PrintableTemplightEntryEnd &EndEntry = aNode.finish;
447 |
448 | std::string EscapedName = escapeXml(BegEntry.Name);
449 | OutputOS << llvm::format("n%d [label = ", aNode.nd_id)
450 | << llvm::format("\"%s\\n"
451 | "%s\\n"
452 | "At %s Line %d Column %d\\n",
453 | SynthesisKindStrings[BegEntry.SynthesisKind],
454 | EscapedName.c_str(), BegEntry.FileName.c_str(),
455 | BegEntry.Line, BegEntry.Column);
456 | if (!BegEntry.TempOri_FileName.empty()) {
457 | OutputOS << llvm::format("From %s Line %d Column %d\\n",
458 | BegEntry.TempOri_FileName.c_str(),
459 | BegEntry.TempOri_Line, BegEntry.TempOri_Column);
460 | }
461 | OutputOS << llvm::format("Time: %.9f seconds Memory: %d bytes\" ];\n",
462 | EndEntry.TimeStamp - BegEntry.TimeStamp,
463 | EndEntry.MemoryUsage - BegEntry.MemoryUsage);
464 |
465 | if (aNode.parent_id == RecordedDFSEntryTree::invalid_id)
466 | return;
467 |
468 | OutputOS << llvm::format("n%d -> n%d;\n", aNode.parent_id, aNode.nd_id);
469 | }
470 |
471 | void TemplightGraphVizWriter::closePrintedTreeNode(
472 | const EntryTraversalTask &aNode) {}
473 |
474 | } // namespace clang
475 |
--------------------------------------------------------------------------------
/utils/ExtraWriters/TemplightExtraWriters.h:
--------------------------------------------------------------------------------
1 | //===- TemplightProtobufWriter.h --------------------*- C++ -*-------------===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #ifndef LLVM_CLANG_TEMPLIGHT_EXTRA_WRITERS_H
11 | #define LLVM_CLANG_TEMPLIGHT_EXTRA_WRITERS_H
12 |
13 | #include "PrintableTemplightEntries.h"
14 |
15 | #include
16 |
17 | #include
18 | #include
19 |
20 | namespace llvm {
21 | namespace yaml {
22 | class Output;
23 | }
24 | } // namespace llvm
25 |
26 | namespace clang {
27 |
28 | class TemplightYamlWriter : public TemplightWriter {
29 | public:
30 | TemplightYamlWriter(llvm::raw_ostream &aOS);
31 | ~TemplightYamlWriter();
32 |
33 | void initialize(const std::string &aSourceName = "") override;
34 | void finalize() override;
35 |
36 | void printEntry(const PrintableTemplightEntryBegin &aEntry) override;
37 | void printEntry(const PrintableTemplightEntryEnd &aEntry) override;
38 |
39 | private:
40 | std::unique_ptr Output;
41 | };
42 |
43 | class TemplightXmlWriter : public TemplightWriter {
44 | public:
45 | TemplightXmlWriter(llvm::raw_ostream &aOS);
46 | ~TemplightXmlWriter();
47 |
48 | void initialize(const std::string &aSourceName = "") override;
49 | void finalize() override;
50 |
51 | void printEntry(const PrintableTemplightEntryBegin &aEntry) override;
52 | void printEntry(const PrintableTemplightEntryEnd &aEntry) override;
53 | };
54 |
55 | class TemplightTextWriter : public TemplightWriter {
56 | public:
57 | TemplightTextWriter(llvm::raw_ostream &aOS);
58 | ~TemplightTextWriter();
59 |
60 | void initialize(const std::string &aSourceName = "") override;
61 | void finalize() override;
62 |
63 | void printEntry(const PrintableTemplightEntryBegin &aEntry) override;
64 | void printEntry(const PrintableTemplightEntryEnd &aEntry) override;
65 | };
66 |
67 | struct RecordedDFSEntryTree;
68 | struct EntryTraversalTask;
69 |
70 | class TemplightTreeWriter : public TemplightWriter {
71 | public:
72 | TemplightTreeWriter(llvm::raw_ostream &aOS);
73 | ~TemplightTreeWriter();
74 |
75 | void initialize(const std::string &aSourceName = "") override;
76 | void finalize() override;
77 |
78 | void printEntry(const PrintableTemplightEntryBegin &aEntry) override;
79 | void printEntry(const PrintableTemplightEntryEnd &aEntry) override;
80 |
81 | protected:
82 | virtual void openPrintedTreeNode(const EntryTraversalTask &aNode) = 0;
83 | virtual void closePrintedTreeNode(const EntryTraversalTask &aNode) = 0;
84 |
85 | virtual void initializeTree(const std::string &aSourceName) = 0;
86 | virtual void finalizeTree() = 0;
87 |
88 | std::unique_ptr p_tree;
89 | };
90 |
91 | class TemplightNestedXMLWriter : public TemplightTreeWriter {
92 | public:
93 | TemplightNestedXMLWriter(llvm::raw_ostream &aOS);
94 | ~TemplightNestedXMLWriter();
95 |
96 | protected:
97 | void openPrintedTreeNode(const EntryTraversalTask &aNode) override;
98 | void closePrintedTreeNode(const EntryTraversalTask &aNode) override;
99 |
100 | void initializeTree(const std::string &aSourceName = "") override;
101 | void finalizeTree() override;
102 | };
103 |
104 | class TemplightGraphMLWriter : public TemplightTreeWriter {
105 | public:
106 | TemplightGraphMLWriter(llvm::raw_ostream &aOS);
107 | ~TemplightGraphMLWriter();
108 |
109 | protected:
110 | void openPrintedTreeNode(const EntryTraversalTask &aNode) override;
111 | void closePrintedTreeNode(const EntryTraversalTask &aNode) override;
112 |
113 | void initializeTree(const std::string &aSourceName = "") override;
114 | void finalizeTree() override;
115 |
116 | private:
117 | int last_edge_id;
118 | };
119 |
120 | class TemplightGraphVizWriter : public TemplightTreeWriter {
121 | public:
122 | TemplightGraphVizWriter(llvm::raw_ostream &aOS);
123 | ~TemplightGraphVizWriter();
124 |
125 | protected:
126 | void openPrintedTreeNode(const EntryTraversalTask &aNode) override;
127 | void closePrintedTreeNode(const EntryTraversalTask &aNode) override;
128 |
129 | void initializeTree(const std::string &aSourceName = "") override;
130 | void finalizeTree() override;
131 | };
132 |
133 | /*
134 | class ProtobufPrinter : public TemplightTracer::TracePrinter {
135 | protected:
136 | void startTraceImpl() override {
137 | // get the source name from the source manager:
138 | FileID fileID = TheSema.getSourceManager().getMainFileID();
139 | std::string src_name =
140 | TheSema.getSourceManager().getFileEntryForID(fileID)->getName();
141 | Writer.initialize(src_name);
142 | };
143 | void endTraceImpl() override {
144 | Writer.finalize();
145 | Writer.dumpOnStream(*this->TraceOS);
146 | };
147 |
148 | void printEntryImpl(const PrintableTemplightEntryBegin& Entry) override {
149 | Writer.printEntry(Entry);
150 | };
151 |
152 | void printEntryImpl(const PrintableTemplightEntryEnd& Entry) override {
153 | Writer.printEntry(Entry);
154 | };
155 |
156 | public:
157 |
158 | ProtobufPrinter(const Sema &aSema, const std::string &Output) :
159 | TemplightTracer::TracePrinter(aSema, Output) { };
160 |
161 | private:
162 | TemplightProtobufWriter Writer;
163 | };
164 | */
165 |
166 | } // namespace clang
167 |
168 | #endif
169 |
--------------------------------------------------------------------------------
/utils/ProtobufReader/TemplightProtobufReader.cpp:
--------------------------------------------------------------------------------
1 | //===- TemplightProtobufWriter.cpp -----------------*- C++ -*--------------===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #include "TemplightProtobufReader.h"
11 |
12 | #include "ThinProtobuf.h"
13 |
14 | #include
15 |
16 | #include
17 | #include
18 |
19 | namespace clang {
20 |
21 | TemplightProtobufReader::TemplightProtobufReader() {}
22 |
23 | void TemplightProtobufReader::loadHeader(llvm::StringRef aSubBuffer) {
24 | // Set default values:
25 | Version = 0;
26 | SourceName = "";
27 |
28 | while (aSubBuffer.size()) {
29 | unsigned int cur_wire = llvm::protobuf::loadVarInt(aSubBuffer);
30 | switch (cur_wire) {
31 | case llvm::protobuf::getVarIntWire<1>::value:
32 | Version = llvm::protobuf::loadVarInt(aSubBuffer);
33 | break;
34 | case llvm::protobuf::getStringWire<2>::value:
35 | SourceName = llvm::protobuf::loadString(aSubBuffer);
36 | break;
37 | default:
38 | llvm::protobuf::skipData(aSubBuffer, cur_wire);
39 | break;
40 | }
41 | }
42 |
43 | LastChunk = TemplightProtobufReader::Header;
44 | }
45 |
46 | void TemplightProtobufReader::loadDictionaryEntry(llvm::StringRef aSubBuffer) {
47 | // Set default values:
48 | std::string name = "";
49 | llvm::SmallVector markers;
50 |
51 | while (aSubBuffer.size()) {
52 | unsigned int cur_wire = llvm::protobuf::loadVarInt(aSubBuffer);
53 | switch (cur_wire) {
54 | case llvm::protobuf::getStringWire<1>::value:
55 | name = llvm::protobuf::loadString(aSubBuffer);
56 | break;
57 | case llvm::protobuf::getVarIntWire<2>::value:
58 | markers.push_back(llvm::protobuf::loadVarInt(aSubBuffer));
59 | break;
60 | default:
61 | llvm::protobuf::skipData(aSubBuffer, cur_wire);
62 | break;
63 | }
64 | }
65 |
66 | std::string::iterator it_name = std::find(name.begin(), name.end(), '\0');
67 | llvm::SmallVector::iterator it_mark = markers.begin();
68 | while ((it_name != name.end()) && (it_mark != markers.end())) {
69 | std::size_t offset = it_name - name.begin();
70 | name.replace(it_name, it_name + 1, templateNameMap[*it_mark]);
71 | it_name = std::find(name.begin() + offset, name.end(), '\0');
72 | ++it_mark;
73 | }
74 |
75 | templateNameMap.push_back(name);
76 | }
77 |
78 | static void loadLocation(llvm::StringRef aSubBuffer,
79 | std::vector &fileNameMap,
80 | std::string &FileName, int &Line, int &Column) {
81 | // Set default values:
82 | FileName = "";
83 | std::size_t FileID = std::numeric_limits::max();
84 | Line = 0;
85 | Column = 0;
86 |
87 | while (aSubBuffer.size()) {
88 | unsigned int cur_wire = llvm::protobuf::loadVarInt(aSubBuffer);
89 | switch (cur_wire) {
90 | case llvm::protobuf::getStringWire<1>::value:
91 | FileName = llvm::protobuf::loadString(aSubBuffer);
92 | break;
93 | case llvm::protobuf::getVarIntWire<2>::value:
94 | FileID = llvm::protobuf::loadVarInt(aSubBuffer);
95 | break;
96 | case llvm::protobuf::getVarIntWire<3>::value:
97 | Line = llvm::protobuf::loadVarInt(aSubBuffer);
98 | break;
99 | case llvm::protobuf::getVarIntWire<4>::value:
100 | Column = llvm::protobuf::loadVarInt(aSubBuffer);
101 | break;
102 | default:
103 | llvm::protobuf::skipData(aSubBuffer, cur_wire);
104 | break;
105 | }
106 | }
107 |
108 | if (FileID != std::numeric_limits::max()) {
109 | if (fileNameMap.size() <= FileID)
110 | fileNameMap.resize(FileID + 1);
111 | if (!FileName.empty()) {
112 | fileNameMap[FileID] =
113 | FileName; // overwrite existing names, if any, but there shouldn't be.
114 | } else {
115 | FileName = fileNameMap[FileID];
116 | }
117 | } // else we don't care?
118 | }
119 |
120 | void TemplightProtobufReader::loadTemplateName(llvm::StringRef aSubBuffer) {
121 | // Set default values:
122 | LastBeginEntry.Name = "";
123 |
124 | while (aSubBuffer.size()) {
125 | unsigned int cur_wire = llvm::protobuf::loadVarInt(aSubBuffer);
126 | switch (cur_wire) {
127 | case llvm::protobuf::getStringWire<1>::value:
128 | LastBeginEntry.Name = llvm::protobuf::loadString(aSubBuffer);
129 | break;
130 | case llvm::protobuf::getStringWire<2>::value: {
131 | LastBeginEntry.Name = llvm::protobuf::loadString(aSubBuffer);
132 | llvm::SmallVector UBuf;
133 | if (llvm::zlib::uncompress(LastBeginEntry.Name, UBuf,
134 | LastBeginEntry.Name.size() * 2) ==
135 | llvm::zlib::StatusOK)
136 | LastBeginEntry.Name.assign(UBuf.begin(), UBuf.end());
137 | else
138 | LastBeginEntry.Name = "";
139 | break;
140 | }
141 | case llvm::protobuf::getVarIntWire<3>::value: {
142 | LastBeginEntry.Name =
143 | templateNameMap[llvm::protobuf::loadVarInt(aSubBuffer)];
144 | break;
145 | }
146 | default:
147 | llvm::protobuf::skipData(aSubBuffer, cur_wire);
148 | break;
149 | }
150 | }
151 | }
152 |
153 | void TemplightProtobufReader::loadBeginEntry(llvm::StringRef aSubBuffer) {
154 | // Set default values:
155 | LastBeginEntry.SynthesisKind = 0;
156 | LastBeginEntry.Name = "";
157 | LastBeginEntry.TimeStamp = 0.0;
158 | LastBeginEntry.MemoryUsage = 0;
159 |
160 | while (aSubBuffer.size()) {
161 | unsigned int cur_wire = llvm::protobuf::loadVarInt(aSubBuffer);
162 | switch (cur_wire) {
163 | case llvm::protobuf::getVarIntWire<1>::value:
164 | LastBeginEntry.SynthesisKind = llvm::protobuf::loadVarInt(aSubBuffer);
165 | break;
166 | case llvm::protobuf::getStringWire<2>::value: {
167 | std::uint64_t cur_size = llvm::protobuf::loadVarInt(aSubBuffer);
168 | loadTemplateName(aSubBuffer.slice(0, cur_size));
169 | aSubBuffer = aSubBuffer.drop_front(cur_size);
170 | break;
171 | }
172 | case llvm::protobuf::getStringWire<3>::value: {
173 | std::uint64_t cur_size = llvm::protobuf::loadVarInt(aSubBuffer);
174 | loadLocation(aSubBuffer.slice(0, cur_size), fileNameMap,
175 | LastBeginEntry.FileName, LastBeginEntry.Line,
176 | LastBeginEntry.Column);
177 | aSubBuffer = aSubBuffer.drop_front(cur_size);
178 | break;
179 | }
180 | case llvm::protobuf::getDoubleWire<4>::value:
181 | LastBeginEntry.TimeStamp = llvm::protobuf::loadDouble(aSubBuffer);
182 | break;
183 | case llvm::protobuf::getVarIntWire<5>::value:
184 | LastBeginEntry.MemoryUsage = llvm::protobuf::loadVarInt(aSubBuffer);
185 | break;
186 | case llvm::protobuf::getStringWire<6>::value: {
187 | std::uint64_t cur_size = llvm::protobuf::loadVarInt(aSubBuffer);
188 | loadLocation(aSubBuffer.slice(0, cur_size), fileNameMap,
189 | LastBeginEntry.TempOri_FileName, LastBeginEntry.TempOri_Line,
190 | LastBeginEntry.TempOri_Column);
191 | aSubBuffer = aSubBuffer.drop_front(cur_size);
192 | break;
193 | }
194 | default:
195 | llvm::protobuf::skipData(aSubBuffer, cur_wire);
196 | break;
197 | }
198 | }
199 |
200 | LastChunk = TemplightProtobufReader::BeginEntry;
201 | }
202 |
203 | void TemplightProtobufReader::loadEndEntry(llvm::StringRef aSubBuffer) {
204 | // Set default values:
205 | LastEndEntry.TimeStamp = 0.0;
206 | LastEndEntry.MemoryUsage = 0;
207 |
208 | while (aSubBuffer.size()) {
209 | unsigned int cur_wire = llvm::protobuf::loadVarInt(aSubBuffer);
210 | switch (cur_wire) {
211 | case llvm::protobuf::getDoubleWire<1>::value:
212 | LastEndEntry.TimeStamp = llvm::protobuf::loadDouble(aSubBuffer);
213 | break;
214 | case llvm::protobuf::getVarIntWire<2>::value:
215 | LastEndEntry.MemoryUsage = llvm::protobuf::loadVarInt(aSubBuffer);
216 | break;
217 | default:
218 | llvm::protobuf::skipData(aSubBuffer, cur_wire);
219 | break;
220 | }
221 | }
222 |
223 | LastChunk = TemplightProtobufReader::EndEntry;
224 | }
225 |
226 | TemplightProtobufReader::LastChunkType
227 | TemplightProtobufReader::startOnBuffer(llvm::StringRef aBuffer) {
228 | buffer = aBuffer;
229 | fileNameMap.clear();
230 | unsigned int cur_wire = llvm::protobuf::loadVarInt(buffer);
231 | if (cur_wire != llvm::protobuf::getStringWire<1>::value) {
232 | buffer = llvm::StringRef();
233 | remainder_buffer = llvm::StringRef();
234 | LastChunk = TemplightProtobufReader::EndOfFile;
235 | return LastChunk;
236 | }
237 | std::uint64_t cur_size = llvm::protobuf::loadVarInt(buffer);
238 | remainder_buffer = buffer.slice(cur_size, buffer.size());
239 | buffer = buffer.slice(0, cur_size);
240 | return next();
241 | }
242 |
243 | TemplightProtobufReader::LastChunkType TemplightProtobufReader::next() {
244 | if (buffer.empty()) {
245 | if (remainder_buffer.empty()) {
246 | LastChunk = TemplightProtobufReader::EndOfFile;
247 | return LastChunk;
248 | } else {
249 | return startOnBuffer(remainder_buffer);
250 | }
251 | }
252 | unsigned int cur_wire = llvm::protobuf::loadVarInt(buffer);
253 | switch (cur_wire) {
254 | case llvm::protobuf::getStringWire<1>::value: {
255 | std::uint64_t cur_size = llvm::protobuf::loadVarInt(buffer);
256 | loadHeader(buffer.slice(0, cur_size));
257 | buffer = buffer.drop_front(cur_size);
258 | return LastChunk;
259 | };
260 | case llvm::protobuf::getStringWire<2>::value: {
261 | std::uint64_t cur_size = llvm::protobuf::loadVarInt(buffer);
262 | llvm::StringRef sub_buffer = buffer.slice(0, cur_size);
263 | buffer = buffer.drop_front(cur_size);
264 | cur_wire = llvm::protobuf::loadVarInt(sub_buffer);
265 | cur_size = llvm::protobuf::loadVarInt(sub_buffer);
266 | switch (cur_wire) {
267 | case llvm::protobuf::getStringWire<1>::value:
268 | loadBeginEntry(sub_buffer);
269 | break;
270 | case llvm::protobuf::getStringWire<2>::value:
271 | loadEndEntry(sub_buffer);
272 | break;
273 | default: // ignore for fwd-compat.
274 | break;
275 | };
276 | return LastChunk;
277 | };
278 | case llvm::protobuf::getStringWire<3>::value: {
279 | std::uint64_t cur_size = llvm::protobuf::loadVarInt(buffer);
280 | loadDictionaryEntry(buffer.slice(0, cur_size));
281 | buffer = buffer.drop_front(cur_size);
282 | LastChunk = TemplightProtobufReader::Other;
283 | return LastChunk;
284 | };
285 | default: { // ignore for fwd-compat.
286 | llvm::protobuf::skipData(buffer, cur_wire);
287 | return next(); // tail-call
288 | };
289 | }
290 | }
291 |
292 | } // namespace clang
293 |
--------------------------------------------------------------------------------
/utils/ProtobufReader/TemplightProtobufReader.h:
--------------------------------------------------------------------------------
1 | //===- TemplightProtobufReader.h --------------------*- C++ -*-------------===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #ifndef LLVM_CLANG_TEMPLIGHT_PROTOBUF_READER_H
11 | #define LLVM_CLANG_TEMPLIGHT_PROTOBUF_READER_H
12 |
13 | #include "PrintableTemplightEntries.h"
14 |
15 | #include
16 |
17 | #include
18 | #include
19 |
20 | namespace clang {
21 |
22 | class TemplightProtobufReader {
23 | private:
24 | llvm::StringRef buffer;
25 | llvm::StringRef remainder_buffer;
26 |
27 | std::vector fileNameMap;
28 | std::vector templateNameMap;
29 |
30 | void loadHeader(llvm::StringRef aSubBuffer);
31 | void loadDictionaryEntry(llvm::StringRef aSubBuffer);
32 | void loadTemplateName(llvm::StringRef aSubBuffer);
33 | void loadBeginEntry(llvm::StringRef aSubBuffer);
34 | void loadEndEntry(llvm::StringRef aSubBuffer);
35 |
36 | public:
37 | enum LastChunkType {
38 | EndOfFile = 0,
39 | Header,
40 | BeginEntry,
41 | EndEntry,
42 | Other
43 | } LastChunk;
44 |
45 | unsigned int Version;
46 | std::string SourceName;
47 |
48 | PrintableTemplightEntryBegin LastBeginEntry;
49 | PrintableTemplightEntryEnd LastEndEntry;
50 |
51 | TemplightProtobufReader();
52 |
53 | LastChunkType startOnBuffer(llvm::StringRef aBuffer);
54 | LastChunkType next();
55 | };
56 |
57 | } // namespace clang
58 |
59 | #endif
60 |
--------------------------------------------------------------------------------
/utils/create_patch.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # This script can be used for re-creating the patch. It assumes, that the source
4 | # code has been checked out as part of the llvm/clang source tree according to
5 | # the tutorial found in README.md of this repository.
6 |
7 | export LANG=C
8 | export LC_MESSAGES=C
9 | export LC_COLLATE=C
10 |
11 | SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
12 | cd "${SCRIPTPATH}/../../../../../"
13 |
14 | VERSIONFILE="${SCRIPTPATH}/../templight_clang_version.txt"
15 |
16 | LLVMGIT="$(git log -1 | grep "commit .*" | awk -v N=2 '{print $N}')"
17 | LLVMSVN="$(git log -1 | grep "git-svn-id: .*" | awk -v N=2 '{print $N}')"
18 | cd tools/clang/
19 | CLANGGIT="$(git log -1 | grep "commit .*" | awk -v N=2 '{print $N}')"
20 | CLANGSVN="$(git log -1 | grep "git-svn-id: .*" | awk -v N=2 '{print $N}')"
21 |
22 | echo "'templight_clang_patch*.diff' was created using the following LLVM/Clang versions:\n" > $VERSIONFILE
23 |
24 | echo "LLVM git: $LLVMGIT" >> $VERSIONFILE
25 | echo "LLVM svn: $LLVMSVN" >> $VERSIONFILE
26 |
27 | echo "Clang git: $CLANGGIT" >> $VERSIONFILE
28 | echo "Clang svn: $CLANGSVN" >> $VERSIONFILE
29 |
30 | git diff > $SCRIPTPATH/../templight_clang_patch.diff
31 | git diff -U999999 > $SCRIPTPATH/../templight_clang_patch_with_context.diff
32 |
33 |
34 |
--------------------------------------------------------------------------------
/utils/format.sh:
--------------------------------------------------------------------------------
1 | for i in c cc cpp h hpp; do
2 | for file in $(find -type f -name "*.$i"); do
3 | clang-format -i $file
4 | done
5 | done
6 |
--------------------------------------------------------------------------------