├── .clang-format ├── .gitignore ├── .travis.yml ├── .ycm_extra_conf.py ├── CMakeLists.txt ├── Doxyfile.in ├── MIT-LICENSE.txt ├── README.md ├── doc ├── main.tex ├── ref.bib └── sig-alternate.cls ├── include ├── AuxGraph.h ├── BreakSelfLoopsPass.h ├── EPPDecode.h ├── EPPEncode.h ├── EPPPathPrinter.h ├── EPPProfile.h └── SplitLandingPadPredsPass.h ├── lib ├── CMakeLists.txt └── epp │ ├── AuxGraph.cpp │ ├── BreakSelfLoopsPass.cpp │ ├── CMakeLists.txt │ ├── EPPDecode.cpp │ ├── EPPEncode.cpp │ ├── EPPPathPrinter.cpp │ ├── EPPProfile.cpp │ ├── Runtime.cpp │ └── SplitLandingPadPredsPass.cpp ├── test ├── CMakeLists.txt ├── lit.cfg ├── lit.site.cfg.in └── srcs │ ├── 01-basic.c │ ├── 01-basic.c.txt │ ├── 02-triangle.c │ ├── 02-triangle.c.txt │ ├── 03-diamond.c │ ├── 03-diamond.c.txt │ ├── 04-diamond-x2.c │ ├── 04-diamond-x2.c.txt │ ├── 05-loop.c │ ├── 05-loop.c.txt │ ├── 06-loop-triangle.c │ ├── 06-loop-triangle.c.txt │ ├── 07-exception.cxx │ ├── 07-exception.cxx.txt │ ├── 08-pthread.c │ ├── 08-pthread.c.txt │ ├── 09-pthread2.c │ ├── 09-pthread2.c.txt │ ├── 10-omp.c │ ├── 10-omp.c.txt │ ├── 11-omp-for.c │ ├── 11-omp-for.c.txt │ ├── 12-thread.cxx │ ├── 12-thread.cxx.txt │ ├── 13-switch.c │ ├── 13-switch.c.txt │ ├── 14-triangle-loop.c │ ├── 14-triangle-loop.c.txt │ ├── 15-crit-ex.cxx │ ├── 15-crit-ex.cxx.txt │ ├── 16-unreach.c │ ├── 16-unreach.c.txt │ └── 17-self-loop.c └── tools ├── CMakeLists.txt └── llvm-epp ├── CMakeLists.txt └── main.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: true 6 | AlignConsecutiveAssignments: true 7 | AlignEscapedNewlinesLeft: false 8 | AlignOperands: true 9 | AlignTrailingComments: true 10 | AllowAllParametersOfDeclarationOnNextLine: true 11 | AllowShortBlocksOnASingleLine: false 12 | AllowShortCaseLabelsOnASingleLine: false 13 | AllowShortIfStatementsOnASingleLine: false 14 | AllowShortLoopsOnASingleLine: false 15 | AllowShortFunctionsOnASingleLine: All 16 | AlwaysBreakAfterDefinitionReturnType: false 17 | AlwaysBreakTemplateDeclarations: false 18 | AlwaysBreakBeforeMultilineStrings: false 19 | BreakBeforeBinaryOperators: None 20 | BreakBeforeTernaryOperators: true 21 | BreakConstructorInitializersBeforeComma: false 22 | BinPackParameters: true 23 | BinPackArguments: true 24 | ColumnLimit: 80 25 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 26 | ConstructorInitializerIndentWidth: 4 27 | DerivePointerAlignment: false 28 | ExperimentalAutoDetectBinPacking: false 29 | IndentCaseLabels: false 30 | IndentWrappedFunctionNames: false 31 | IndentFunctionDeclarationAfterType: false 32 | MaxEmptyLinesToKeep: 1 33 | KeepEmptyLinesAtTheStartOfBlocks: true 34 | NamespaceIndentation: None 35 | ObjCBlockIndentWidth: 2 36 | ObjCSpaceAfterProperty: false 37 | ObjCSpaceBeforeProtocolList: true 38 | PenaltyBreakBeforeFirstCallParameter: 19 39 | PenaltyBreakComment: 300 40 | PenaltyBreakString: 1000 41 | PenaltyBreakFirstLessLess: 120 42 | PenaltyExcessCharacter: 1000000 43 | PenaltyReturnTypeOnItsOwnLine: 60 44 | PointerAlignment: Right 45 | SpacesBeforeTrailingComments: 1 46 | Cpp11BracedListStyle: true 47 | Standard: Cpp11 48 | IndentWidth: 4 49 | TabWidth: 4 50 | UseTab: Never 51 | BreakBeforeBraces: Attach 52 | SpacesInParentheses: false 53 | SpacesInSquareBrackets: false 54 | SpacesInAngles: false 55 | SpaceInEmptyParentheses: false 56 | SpacesInCStyleCastParentheses: false 57 | SpaceAfterCStyleCast: false 58 | SpacesInContainerLiterals: true 59 | SpaceBeforeAssignmentOperators: true 60 | ContinuationIndentWidth: 4 61 | CommentPragmas: '^ IWYU pragma:' 62 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 63 | SpaceBeforeParens: ControlStatements 64 | DisableFormat: false 65 | ... 66 | 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | *.smod 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | 31 | # Python 32 | *.pyc 33 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | sudo: required 3 | dist: trusty 4 | compiler: 5 | - g++ 6 | os: 7 | - linux 8 | before_script: 9 | - sudo unlink /usr/bin/gcc && sudo ln -s /usr/bin/gcc-5 /usr/bin/gcc 10 | - sudo unlink /usr/bin/g++ && sudo ln -s /usr/bin/g++-5 /usr/bin/g++ 11 | - g++ --version 12 | - wget http://releases.llvm.org/4.0.0/clang+llvm-4.0.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz 13 | - tar xf clang+llvm-4.0.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz 14 | - export PATH=${PWD}/clang+llvm-4.0.0-x86_64-linux-gnu-ubuntu-14.04/bin:$PATH 15 | - export LD_LIBRARY_PATH=${PWD}/clang+llvm-4.0.0-x86_64-linux-gnu-ubuntu-14.04/lib 16 | - cmake -DLLVM_DIR=clang+llvm-4.0.0-x86_64-linux-gnu-ubuntu-14.04/lib/cmake/llvm . 17 | - sudo pip install lit 18 | script: 19 | - make -j4 VERBOSE=1 20 | - lit test -v 21 | branches: 22 | only: 23 | - master 24 | addons: 25 | apt: 26 | sources: 27 | - ubuntu-toolchain-r-test 28 | packages: 29 | - gcc-5 30 | - g++-5 31 | - cmake 32 | notifications: 33 | email: false 34 | -------------------------------------------------------------------------------- /.ycm_extra_conf.py: -------------------------------------------------------------------------------- 1 | # Generated by YCM Generator at 2017-02-08 22:21:21.129815 2 | 3 | # This file is NOT licensed under the GPLv3, which is the license for the rest 4 | # of YouCompleteMe. 5 | # 6 | # Here's the license text for this file: 7 | # 8 | # This is free and unencumbered software released into the public domain. 9 | # 10 | # Anyone is free to copy, modify, publish, use, compile, sell, or 11 | # distribute this software, either in source code form or as a compiled 12 | # binary, for any purpose, commercial or non-commercial, and by any 13 | # means. 14 | # 15 | # In jurisdictions that recognize copyright laws, the author or authors 16 | # of this software dedicate any and all copyright interest in the 17 | # software to the public domain. We make this dedication for the benefit 18 | # of the public at large and to the detriment of our heirs and 19 | # successors. We intend this dedication to be an overt act of 20 | # relinquishment in perpetuity of all present and future rights to this 21 | # software under copyright law. 22 | # 23 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 26 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 27 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 28 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 29 | # OTHER DEALINGS IN THE SOFTWARE. 30 | # 31 | # For more information, please refer to 32 | 33 | import os 34 | import ycm_core 35 | 36 | flags = [ 37 | '-x', 38 | 'c++', 39 | '-D_GNU_SOURCE', 40 | '-D__STDC_CONSTANT_MACROS', 41 | '-D__STDC_FORMAT_MACROS', 42 | '-D__STDC_LIMIT_MACROS', 43 | '-Depp_rt_agg_EXPORTS', 44 | '-Depp_rt_rle_EXPORTS', 45 | '-I/home/ska124/ModuleInstall/llvm-5.0/include', 46 | '-I/home/ska124/Repos/llvm-epp/include', 47 | '-Werror', 48 | '-Wno-deprecated-declarations', 49 | '-std=c++1y', 50 | ] 51 | 52 | 53 | # Set this to the absolute path to the folder (NOT the file!) containing the 54 | # compile_commands.json file to use that instead of 'flags'. See here for 55 | # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html 56 | # 57 | # You can get CMake to generate this file for you by adding: 58 | # set( CMAKE_EXPORT_COMPILE_COMMANDS 1 ) 59 | # to your CMakeLists.txt file. 60 | # 61 | # Most projects will NOT need to set this to anything; you can just change the 62 | # 'flags' list of compilation flags. Notice that YCM itself uses that approach. 63 | compilation_database_folder = '' 64 | 65 | if os.path.exists( compilation_database_folder ): 66 | database = ycm_core.CompilationDatabase( compilation_database_folder ) 67 | else: 68 | database = None 69 | 70 | SOURCE_EXTENSIONS = [ '.C', '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ] 71 | 72 | def DirectoryOfThisScript(): 73 | return os.path.dirname( os.path.abspath( __file__ ) ) 74 | 75 | 76 | def MakeRelativePathsInFlagsAbsolute( flags, working_directory ): 77 | if not working_directory: 78 | return list( flags ) 79 | new_flags = [] 80 | make_next_absolute = False 81 | path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ] 82 | for flag in flags: 83 | new_flag = flag 84 | 85 | if make_next_absolute: 86 | make_next_absolute = False 87 | if not flag.startswith( '/' ): 88 | new_flag = os.path.join( working_directory, flag ) 89 | 90 | for path_flag in path_flags: 91 | if flag == path_flag: 92 | make_next_absolute = True 93 | break 94 | 95 | if flag.startswith( path_flag ): 96 | path = flag[ len( path_flag ): ] 97 | new_flag = path_flag + os.path.join( working_directory, path ) 98 | break 99 | 100 | if new_flag: 101 | new_flags.append( new_flag ) 102 | return new_flags 103 | 104 | 105 | def IsHeaderFile( filename ): 106 | extension = os.path.splitext( filename )[ 1 ] 107 | return extension in [ '.H', '.h', '.hxx', '.hpp', '.hh' ] 108 | 109 | 110 | def GetCompilationInfoForFile( filename ): 111 | # The compilation_commands.json file generated by CMake does not have entries 112 | # for header files. So we do our best by asking the db for flags for a 113 | # corresponding source file, if any. If one exists, the flags for that file 114 | # should be good enough. 115 | if IsHeaderFile( filename ): 116 | basename = os.path.splitext( filename )[ 0 ] 117 | for extension in SOURCE_EXTENSIONS: 118 | replacement_file = basename + extension 119 | if os.path.exists( replacement_file ): 120 | compilation_info = database.GetCompilationInfoForFile( 121 | replacement_file ) 122 | if compilation_info.compiler_flags_: 123 | return compilation_info 124 | return None 125 | return database.GetCompilationInfoForFile( filename ) 126 | 127 | 128 | def FlagsForFile( filename, **kwargs ): 129 | if database: 130 | # Bear in mind that compilation_info.compiler_flags_ does NOT return a 131 | # python list, but a "list-like" StringVec object 132 | compilation_info = GetCompilationInfoForFile( filename ) 133 | if not compilation_info: 134 | return None 135 | 136 | final_flags = MakeRelativePathsInFlagsAbsolute( 137 | compilation_info.compiler_flags_, 138 | compilation_info.compiler_working_dir_ ) 139 | 140 | else: 141 | relative_to = DirectoryOfThisScript() 142 | final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to ) 143 | 144 | return { 145 | 'flags': final_flags, 146 | 'do_cache': True 147 | } 148 | 149 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(llvm-epp) 2 | cmake_minimum_required(VERSION 2.8) 3 | 4 | set(PACKAGE_NAME llvm-epp) 5 | set(PACKAGE_VERSION 1.0) 6 | set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") 7 | set(PACKAGE_BUGREPORT "ska124@sfu.ca") 8 | 9 | # LLVM 3.8 downloaded from the releases page is built using the older version 10 | # of the CXX ABI, here we disable it. When we use a newer version this option 11 | # will be removed. 12 | set(CMAKE_CXX_FLAGS "-fno-rtti -std=c++1y -Werror -Wno-deprecated-declarations") 13 | 14 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 15 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 16 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 17 | 18 | set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/" ${CMAKE_MODULE_PATH}) 19 | ############## LLVM CONFIGURATION ################# 20 | 21 | # LLVM_DIR must be set to the prefix of /share/llvm/cmake via commandline 22 | find_package(LLVM REQUIRED CONFIG) 23 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 24 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 25 | 26 | # We incorporate the CMake features provided by LLVM: 27 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 28 | include(AddLLVM) 29 | 30 | #option(LLVM_ENABLE_CXX11 "Enable C++11" ON) 31 | 32 | option(LLVM_INCLUDE_TOOLS "Generate build targets for the LLVM tools." ON) 33 | option(LLVM_BUILD_TOOLS 34 | "Build the LLVM tools. If OFF, just generate build targets." ON) 35 | 36 | message("LLVM STATUS: 37 | Definitions ${LLVM_DEFINITIONS} 38 | Includes ${LLVM_INCLUDE_DIRS} 39 | Libraries ${LLVM_LIBRARY_DIRS} 40 | Targets ${LLVM_TARGETS_TO_BUILD}") 41 | # Now set the LLVM header and library paths: 42 | include_directories( ${LLVM_INCLUDE_DIRS} ) 43 | link_directories( ${LLVM_LIBRARY_DIRS} ) 44 | add_definitions( ${LLVM_DEFINITIONS} ) 45 | 46 | 47 | 48 | 49 | find_program(LIT_COMMAND lit) 50 | 51 | # Documentation 52 | 53 | find_package(Doxygen) 54 | if(DOXYGEN_FOUND AND DOXYGEN_DOT_FOUND) 55 | message(STATUS "Doxygen found, the `doc` target is available to generate html documentation") 56 | configure_file(${CMAKE_SOURCE_DIR}/Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile @ONLY) 57 | add_custom_target(doc 58 | ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile 59 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 60 | COMMENT "Generating API documentation for needle" VERBATIM 61 | ) 62 | endif() 63 | 64 | 65 | ############## FINAL PROJECT CONFIG ################# 66 | 67 | # And the project header and library paths 68 | include_directories(${CMAKE_SOURCE_DIR}/include) 69 | link_directories( ${LIBRARY_OUTPUT_PATH} ) 70 | set(CMAKE_TEMP_LIBRARY_PATH "${PROJECT_BINARY_DIR}/lib") 71 | # TODO: Add install path to the list.... 72 | 73 | 74 | add_subdirectory(lib) 75 | add_subdirectory(tools) 76 | add_subdirectory(test) 77 | -------------------------------------------------------------------------------- /MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2017 Snehasish Kumar 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## llvm-epp 2 | Efficient Path Profiling using LLVM 3 | 4 | ## Requires 5 | 6 | 1. LLVM 5.0 7 | 2. gcc-5+ 8 | 9 | ## Build 10 | 11 | 1. `mkdir build && cd build` 12 | 2. `cmake -DCMAKE_BUILD_TYPE=Release .. && make -j 8` 13 | 3. `sudo make install` 14 | 15 | ## Test 16 | 17 | To run the tests, install [lit](https://pypi.python.org/pypi/lit) from the python package index. 18 | 19 | 1. `pip install lit` 20 | 2. `cd build` 21 | 3. `lit test` 22 | 23 | ## Documentation 24 | 25 | To generate documentation, install [graphviz](http://www.graphviz.org/) and [doxygen](http://www.stack.nl/~dimitri/doxygen/). Running `cmake` with these prerequisites will enable the `doc` target for the build system. Running `make doc` will generate html documentation of the classes. 26 | 27 | ## Usage 28 | 29 | 1. `clang -c -g -emit-llvm prog.c` 30 | 2. `llvm-epp prog.bc -o prog` 31 | 3. `clang prog.epp.bc -o exe -lepp-rt` 32 | 4. `./exe` 33 | 5. `llvm-epp -p=path-profile-results.txt prog.bc` 34 | 35 | ## Known Issues 36 | 37 | 1. Instrumentation cannot be placed along computed indirect branch target edges. [This](http://blog.llvm.org/2010/01/address-of-label-and-indirect-branches.html) blog post describes the issue under the section "How does this extension interact with critical edge splitting?". 38 | 39 | ## License 40 | 41 | The MIT License 42 | 43 | -------------------------------------------------------------------------------- /doc/main.tex: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % This is the template for submission to ISCA 2016 3 | % The cls file is a modified from 'sig-alternate.cls' 4 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5 | 6 | 7 | \documentclass{sig-alternate} 8 | \usepackage{mathptmx} % This is Times font 9 | 10 | \newcommand{\ignore}[1]{} 11 | \usepackage{fancyhdr} 12 | \usepackage[normalem]{ulem} 13 | \usepackage[hyphens]{url} 14 | \usepackage{hyperref} 15 | 16 | 17 | %%%%%%%%%%%---SETME-----%%%%%%%%%%%%% 18 | \newcommand{\hpcasubmissionnumber}{NaN} 19 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 20 | 21 | \fancypagestyle{firstpage}{ 22 | \fancyhf{} 23 | \setlength{\headheight}{10pt} 24 | \renewcommand{\headrulewidth}{0pt} 25 | \fancyhead[C]{\normalsize{ISCA 2016 Submission 26 | \textbf{\#\hpcasubmissionnumber} \\ Confidential Draft: DO NOT DISTRIBUTE}} 27 | \pagenumbering{arabic} 28 | } 29 | 30 | %%%%%%%%%%%---SETME-----%%%%%%%%%%%%% 31 | \title{Efficient Path Profiling for LLVM} 32 | \author{Snehasish Kumar, Nick Sumner\\\{ska124,wsumner\}@cs.sfu.ca} 33 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 34 | 35 | \begin{document} 36 | \maketitle 37 | %\thispagestyle{firstpage} 38 | \pagestyle{plain} 39 | \begin{abstract} 40 | 41 | This document is intended to serve as a sample for submissions to ISCA 2016. We provide some guidelines that authors should follow when submitting papers to the conference. In an effort to respect the efforts of reviewers and in the interest of fairness to all prospective authors, we request that all submissions follow the formatting and submission rules detailed below. 42 | 43 | \end{abstract} 44 | 45 | \section{Introduction} 46 | 47 | \subsection{About this document} 48 | 49 | \section{Implementation} 50 | 51 | \section{Evaluation of overheads} 52 | 53 | \section{Roadmap} 54 | 55 | %%%%%%%%% -- BIB STYLE AND FILE -- %%%%%%%% 56 | \bibliographystyle{ieeetr} 57 | \bibliography{ref} 58 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 59 | 60 | \end{document} 61 | -------------------------------------------------------------------------------- /doc/ref.bib: -------------------------------------------------------------------------------- 1 | 2 | 3 | @book{lamport94, 4 | author = "Leslie Lamport", 5 | title = "{\LaTeX: A Document Preparation System}", 6 | year = "1994", 7 | publisher = "Addison-Wesley", 8 | edition = "2nd", 9 | address = "Reading, Massachusetts" 10 | } 11 | 12 | @inproceedings{nicepaper1, 13 | author = "Firstname1 Lastname1 and Firstname2 Lastname2", 14 | title = "A Very Nice Paper To Cite", 15 | month = "Feb.", 16 | year = "2014", 17 | booktitle = "Intl. Symp. on High Performance Computer Architecture (HPCA)" 18 | } 19 | 20 | @inproceedings{nicepaper2, 21 | author = "Firstname1 Lastname1 and Firstname2 Lastname2 and Firstname3 Lastname3", 22 | title = "Another Very Nice Paper to Cite", 23 | month = "Oct.", 24 | year = "2012", 25 | booktitle = "Intl. Symp. on Microarchitecture (MICRO)" 26 | } 27 | 28 | @inproceedings{nicepaper3, 29 | author = "Firstname1 Lastname1 and Firstname2 Lastname2 and Firstname3 Lastname3 and Firstname4 Lastname4 and Firstname5 Lastname5", 30 | title = "Yet Another Very Nice Paper To Cite, With Many Author Names All Spelled Out", 31 | month = "June", 32 | year = "2011", 33 | booktitle = "Intl. Symp. on Computer Architecture (ISCA)" 34 | } 35 | -------------------------------------------------------------------------------- /doc/sig-alternate.cls: -------------------------------------------------------------------------------- 1 | %rabi SIG-ALTERNATE.CLS - VERSION 2.5 2 | % "COMPATIBLE" WITH THE "ACM_PROC_ARTICLE-SP.CLS" V3.2SP 3 | % Gerald Murray - May 23rd 2012 4 | % 5 | % ---- Start of 'updates' ---- 6 | % Changed $10 fee to $15 -- May 2012 -- Gerry 7 | % Changed $5 fee to $10 -- April 2009 -- Gerry 8 | % April 22nd. 2009 - Fixed 'Natbib' incompatibility problem - Gerry 9 | % April 22nd. 2009 - Fixed 'Babel' incompatibility problem - Gerry 10 | % April 22nd. 2009 - Inserted various bug-fixes and improvements - Gerry 11 | % 12 | % To produce Type 1 fonts in the document plus allow for 'normal LaTeX accenting' in the critical areas; 13 | % title, author block, section-heads, confname, etc. etc. 14 | % i.e. the whole purpose of this version update is to NOT resort to 'inelegant accent patches'. 15 | % After much research, three extra .sty packages were added to the the tail (ae, aecompl, aeguill) to solve, 16 | % in particular, the accenting problem(s). We _could_ ask authors (via instructions/sample file) to 'include' these in 17 | % the source .tex file - in the preamble - but if everything is already provided ('behind the scenes' - embedded IN the .cls) 18 | % then this is less work for authors and also makes everything appear 'vanilla'. 19 | % NOTE: all 'patchwork accenting" has been commented out (here) and is no longer 'used' in the sample .tex file (either). 20 | % Gerry June 2007 21 | % 22 | % Patch for accenting in conference name/location. Gerry May 3rd. 2007 23 | % Rule widths changed to .5, author count (>6) fixed, roll-back for Type 3 problem. Gerry March 20th. 2007 24 | % Changes made to 'modernize' the fontnames but esp. for MikTeX users V2.4/2.5 - Nov. 30th. 2006 25 | % Updated the \email definition to allow for its use inside of 'shared affiliations' - Nov. 30th. 2006 26 | % Fixed the 'section number depth value' - Nov. 30th. 2006 27 | % 28 | % Footnotes inside table cells using \minipage (Oct. 2002) 29 | % Georgia fixed bug in sub-sub-section numbering in paragraphs (July 29th. 2002) 30 | % JS/GM fix to vertical spacing before Proofs (July 30th. 2002) 31 | % 32 | % Made the Permission Statement / Conference Info / Copyright Info 33 | % 'user definable' in the source .tex file OR automatic if 34 | % not specified. 35 | % 36 | % Allowance made to switch default fonts between those systems using 37 | % normal/modern font names and those using 'Type 1' or 'Truetype' fonts. 38 | % See LINE NUMBER 255 for details. 39 | % Also provided for enumerated/annotated Corollaries 'surrounded' by 40 | % enumerated Theorems (line 848). 41 | % Gerry November 11th. 1999 42 | % 43 | % ---- End of 'updates' ---- 44 | % 45 | \def\fileversion{v2.5} % for ACM's tracking purposes 46 | \def\filedate{May 23, 2012} % Gerry Murray's tracking data 47 | \def\docdate {Wednesday 23rd. May 2012} % Gerry Murray (with deltas to doc} 48 | \usepackage{epsfig} 49 | \usepackage{amssymb} 50 | \usepackage{amsmath} 51 | \usepackage{amsfonts} 52 | % Need this for accents in Arial/Helvetica 53 | %\usepackage[T1]{fontenc} % Gerry March 12, 2007 - causes Type 3 problems (body text) 54 | %\usepackage{textcomp} 55 | % 56 | % SIG-ALTERNATE DOCUMENT STYLE 57 | % G.K.M. Tobin August-October 1999 58 | % adapted from ARTICLE document style by Ken Traub, Olin Shivers 59 | % also using elements of esub2acm.cls 60 | % HEAVILY MODIFIED, SUBSEQUENTLY, BY GERRY MURRAY 2000 61 | % ARTICLE DOCUMENT STYLE -- Released 16 March 1988 62 | % for LaTeX version 2.09 63 | % Copyright (C) 1988 by Leslie Lamport 64 | % 65 | % 66 | %%% sig-alternate.cls is an 'ALTERNATE' document style for producing 67 | %%% two-column camera-ready pages for ACM conferences. 68 | %%% THIS FILE DOES NOT STRICTLY ADHERE TO THE SIGS (BOARD-ENDORSED) 69 | %%% PROCEEDINGS STYLE. It has been designed to produce a 'tighter' 70 | %%% paper in response to concerns over page budgets. 71 | %%% The main features of this style are: 72 | %%% 73 | %%% 1) Two columns. 74 | %%% 2) Side and top margins of 4.5pc, bottom margin of 6pc, column gutter of 75 | %%% 2pc, hence columns are 20pc wide and 55.5pc tall. (6pc =3D 1in, approx) 76 | %%% 3) First page has title information, and an extra 6pc of space at the 77 | %%% bottom of the first column for the ACM copyright notice. 78 | %%% 4) Text is 9pt on 10pt baselines; titles (except main) are 9pt bold. 79 | %%% 80 | %%% 81 | %%% There are a few restrictions you must observe: 82 | %%% 83 | %%% 1) You cannot change the font size; ACM wants you to use 9pt. 84 | %%% 3) You must start your paper with the \maketitle command. Prior to the 85 | %%% \maketitle you must have \title and \author commands. If you have a 86 | %%% \date command it will be ignored; no date appears on the paper, since 87 | %%% the proceedings will have a date on the front cover. 88 | %%% 4) Marginal paragraphs, tables of contents, lists of figures and tables, 89 | %%% and page headings are all forbidden. 90 | %%% 5) The `figure' environment will produce a figure one column wide; if you 91 | %%% want one that is two columns wide, use `figure*'. 92 | %%% 93 | % 94 | %%% Copyright Space: 95 | %%% This style automatically reserves 1" blank space at the bottom of page 1/ 96 | %%% column 1. This space can optionally be filled with some text using the 97 | %%% \toappear{...} command. If used, this command must be BEFORE the \maketitle 98 | %%% command. If this command is defined AND [preprint] is on, then the 99 | %%% space is filled with the {...} text (at the bottom); otherwise, it is 100 | %%% blank. If you use \toappearbox{...} instead of \toappear{...} then a 101 | %%% box will be drawn around the text (if [preprint] is on). 102 | %%% 103 | %%% A typical usage looks like this: 104 | %%% \toappear{To appear in the Ninth AES Conference on Medievil Lithuanian 105 | %%% Embalming Technique, June 1991, Alfaretta, Georgia.} 106 | %%% This will be included in the preprint, and left out of the conference 107 | %%% version. 108 | %%% 109 | %%% WARNING: 110 | %%% Some dvi-ps converters heuristically allow chars to drift from their 111 | %%% true positions a few pixels. This may be noticeable with the 9pt sans-serif 112 | %%% bold font used for section headers. 113 | %%% You may turn this hackery off via the -e option: 114 | %%% dvips -e 0 foo.dvi >foo.ps 115 | %%% 116 | \typeout{Document Class 'sig-alternate' <23rd. May '12>. Modified by G.K.M. Tobin/Gerry Murray} 117 | \typeout{Based in part upon document Style `acmconf' <22 May 89>. Hacked 4/91 by} 118 | \typeout{shivers@cs.cmu.edu, 4/93 by theobald@cs.mcgill.ca} 119 | \typeout{Excerpts were taken from (Journal Style) 'esub2acm.cls'.} 120 | \typeout{****** Bugs/comments/suggestions/technicalities to Gerry Murray -- murray@hq.acm.org ******} 121 | \typeout{Questions on the style, SIGS policies, etc. to Adrienne Griscti griscti@acm.org} 122 | \oddsidemargin 4.5pc 123 | \evensidemargin 4.5pc 124 | \advance\oddsidemargin by -1in % Correct for LaTeX gratuitousness 125 | \advance\evensidemargin by -1in % Correct for LaTeX gratuitousness 126 | \marginparwidth 0pt % Margin pars are not allowed. 127 | \marginparsep 11pt % Horizontal space between outer margin and 128 | % marginal note 129 | 130 | % Top of page: 131 | \topmargin 4.5pc % Nominal distance from top of page to top of 132 | % box containing running head. 133 | \advance\topmargin by -1in % Correct for LaTeX gratuitousness 134 | \headheight 0pt % Height of box containing running head. 135 | \headsep 0pt % Space between running head and text. 136 | % Bottom of page: 137 | \footskip 30pt % Distance from baseline of box containing foot 138 | % to baseline of last line of text. 139 | \@ifundefined{footheight}{\newdimen\footheight}{}% this is for LaTeX2e 140 | \footheight 12pt % Height of box containing running foot. 141 | 142 | %% Must redefine the top margin so there's room for headers and 143 | %% page numbers if you are using the preprint option. Footers 144 | %% are OK as is. Olin. 145 | \advance\topmargin by -37pt % Leave 37pt above text for headers 146 | \headheight 12pt % Height of box containing running head. 147 | \headsep 25pt % Space between running head and text. 148 | 149 | \textheight 666pt % 9 1/4 column height 150 | \textwidth 42pc % Width of text line. 151 | % For two-column mode: 152 | \columnsep 2pc % Space between columns 153 | \columnseprule 0pt % Width of rule between columns. 154 | \hfuzz 1pt % Allow some variation in column width, otherwise it's 155 | % too hard to typeset in narrow columns. 156 | 157 | \footnotesep 5.6pt % Height of strut placed at the beginning of every 158 | % footnote =3D height of normal \footnotesize strut, 159 | % so no extra space between footnotes. 160 | 161 | \skip\footins 8.1pt plus 4pt minus 2pt % Space between last line of text and 162 | % top of first footnote. 163 | \floatsep 11pt plus 2pt minus 2pt % Space between adjacent floats moved 164 | % to top or bottom of text page. 165 | \textfloatsep 18pt plus 2pt minus 4pt % Space between main text and floats 166 | % at top or bottom of page. 167 | \intextsep 11pt plus 2pt minus 2pt % Space between in-text figures and 168 | % text. 169 | \@ifundefined{@maxsep}{\newdimen\@maxsep}{}% this is for LaTeX2e 170 | \@maxsep 18pt % The maximum of \floatsep, 171 | % \textfloatsep and \intextsep (minus 172 | % the stretch and shrink). 173 | \dblfloatsep 11pt plus 2pt minus 2pt % Same as \floatsep for double-column 174 | % figures in two-column mode. 175 | \dbltextfloatsep 18pt plus 2pt minus 4pt% \textfloatsep for double-column 176 | % floats. 177 | \@ifundefined{@dblmaxsep}{\newdimen\@dblmaxsep}{}% this is for LaTeX2e 178 | \@dblmaxsep 18pt % The maximum of \dblfloatsep and 179 | % \dbltexfloatsep. 180 | \@fptop 0pt plus 1fil % Stretch at top of float page/column. (Must be 181 | % 0pt plus ...) 182 | \@fpsep 8pt plus 2fil % Space between floats on float page/column. 183 | \@fpbot 0pt plus 1fil % Stretch at bottom of float page/column. (Must be 184 | % 0pt plus ... ) 185 | \@dblfptop 0pt plus 1fil % Stretch at top of float page. (Must be 0pt plus ...) 186 | \@dblfpsep 8pt plus 2fil % Space between floats on float page. 187 | \@dblfpbot 0pt plus 1fil % Stretch at bottom of float page. (Must be 188 | % 0pt plus ... ) 189 | \marginparpush 5pt % Minimum vertical separation between two marginal 190 | % notes. 191 | 192 | \parskip 0pt plus 1pt % Extra vertical space between paragraphs. 193 | \parindent 10pt % GM July 2000 / was 0pt - width of paragraph indentation. 194 | \partopsep 2pt plus 1pt minus 1pt% Extra vertical space, in addition to 195 | % \parskip and \topsep, added when user 196 | % leaves blank line before environment. 197 | 198 | \@lowpenalty 51 % Produced by \nopagebreak[1] or \nolinebreak[1] 199 | \@medpenalty 151 % Produced by \nopagebreak[2] or \nolinebreak[2] 200 | \@highpenalty 301 % Produced by \nopagebreak[3] or \nolinebreak[3] 201 | 202 | \@beginparpenalty -\@lowpenalty % Before a list or paragraph environment. 203 | \@endparpenalty -\@lowpenalty % After a list or paragraph environment. 204 | \@itempenalty -\@lowpenalty % Between list items. 205 | 206 | %\@namedef{ds@10pt}{\@latexerr{The `10pt' option is not allowed in the `acmconf' 207 | %\@namedef{ds@10pt}{\ClassError{The `10pt' option is not allowed in the `acmconf' % January 2008 208 | % document style.}\@eha} 209 | %\@namedef{ds@11pt}{\@latexerr{The `11pt' option is not allowed in the `acmconf' 210 | \@namedef{ds@11pt}{\ClassError{The `11pt' option is not allowed in the `acmconf' % January 2008 211 | document style.}\@eha} 212 | %\@namedef{ds@12pt}{\@latexerr{The `12pt' option is not allowed in the `acmconf' 213 | \@namedef{ds@12pt}{\ClassError{The `12pt' option is not allowed in the `acmconf' % January 2008 214 | document style.}\@eha} 215 | 216 | \@options 217 | 218 | \lineskip 2pt % \lineskip is 1pt for all font sizes. 219 | \normallineskip 2pt 220 | \def\baselinestretch{1} 221 | 222 | \abovedisplayskip 10pt plus2pt minus4.5pt% 223 | \belowdisplayskip \abovedisplayskip 224 | \abovedisplayshortskip \z@ plus3pt% 225 | \belowdisplayshortskip 5.4pt plus3pt minus3pt% 226 | \let\@listi\@listI % Setting of \@listi added 9 Jun 87 227 | 228 | \def\small{\@setsize\small{9pt}\viiipt\@viiipt 229 | \abovedisplayskip 7.6pt plus 3pt minus 4pt% 230 | \belowdisplayskip \abovedisplayskip 231 | \abovedisplayshortskip \z@ plus2pt% 232 | \belowdisplayshortskip 3.6pt plus2pt minus 2pt 233 | \def\@listi{\leftmargin\leftmargini %% Added 22 Dec 87 234 | \topsep 4pt plus 2pt minus 2pt\parsep 2pt plus 1pt minus 1pt 235 | \itemsep \parsep}} 236 | 237 | \def\refsmall{\@setsize\small{8pt}\viiipt\@viiipt 238 | \abovedisplayskip 7.6pt plus 3pt minus 4pt% 239 | \belowdisplayskip \abovedisplayskip 240 | \abovedisplayshortskip \z@ plus2pt% 241 | \belowdisplayshortskip 3.6pt plus2pt minus 2pt 242 | \def\@listi{\leftmargin\leftmargini %% Added 22 Dec 87 243 | \topsep 4pt plus 2pt minus 2pt\parsep 2pt plus 1pt minus 1pt 244 | \itemsep \parsep}} 245 | 246 | \def\footnotesize{\@setsize\footnotesize{9pt}\ixpt\@ixpt 247 | \abovedisplayskip 6.4pt plus 2pt minus 4pt% 248 | \belowdisplayskip \abovedisplayskip 249 | \abovedisplayshortskip \z@ plus 1pt% 250 | \belowdisplayshortskip 2.7pt plus 1pt minus 2pt 251 | \def\@listi{\leftmargin\leftmargini %% Added 22 Dec 87 252 | \topsep 3pt plus 1pt minus 1pt\parsep 2pt plus 1pt minus 1pt 253 | \itemsep \parsep}} 254 | 255 | \newcount\aucount 256 | \newcount\originalaucount 257 | \newdimen\auwidth 258 | \auwidth=\textwidth 259 | \newdimen\auskip 260 | \newcount\auskipcount 261 | \newdimen\auskip 262 | \global\auskip=1pc 263 | \newdimen\allauboxes 264 | \allauboxes=\auwidth 265 | \newtoks\addauthors 266 | \newcount\addauflag 267 | \global\addauflag=0 %Haven't shown additional authors yet 268 | 269 | \newtoks\subtitletext 270 | \gdef\subtitle#1{\subtitletext={#1}} 271 | 272 | \gdef\additionalauthors#1{\addauthors={#1}} 273 | 274 | \gdef\numberofauthors#1{\global\aucount=#1 275 | \ifnum\aucount>3\global\originalaucount=\aucount \global\aucount=3\fi %g} % 3 OK - Gerry March 2007 276 | \global\auskipcount=\aucount\global\advance\auskipcount by 1 277 | \global\multiply\auskipcount by 2 278 | \global\multiply\auskip by \auskipcount 279 | \global\advance\auwidth by -\auskip 280 | \global\divide\auwidth by \aucount} 281 | 282 | % \and was modified to count the number of authors. GKMT 12 Aug 1999 283 | \def\alignauthor{% % \begin{tabular} 284 | \end{tabular}% 285 | \begin{tabular}[t]{p{\auwidth}}\centering}% 286 | 287 | % *** NOTE *** NOTE *** NOTE *** NOTE *** 288 | % If you have 'font problems' then you may need 289 | % to change these, e.g. 'arialb' instead of "arialbd". 290 | % Gerry Murray 11/11/1999 291 | % *** OR ** comment out block A and activate block B or vice versa. 292 | % ********************************************** 293 | % 294 | % -- Start of block A -- (Type 1 or Truetype fonts) 295 | %\newfont{\secfnt}{timesbd at 12pt} % was timenrb originally - now is timesbd 296 | %\newfont{\secit}{timesbi at 12pt} %13 Jan 00 gkmt 297 | %\newfont{\subsecfnt}{timesi at 11pt} % was timenrri originally - now is timesi 298 | %\newfont{\subsecit}{timesbi at 11pt} % 13 Jan 00 gkmt -- was times changed to timesbi gm 2/4/2000 299 | % % because "normal" is italic, "italic" is Roman 300 | %\newfont{\ttlfnt}{arialbd at 18pt} % was arialb originally - now is arialbd 301 | %\newfont{\ttlit}{arialbi at 18pt} % 13 Jan 00 gkmt 302 | %\newfont{\subttlfnt}{arial at 14pt} % was arialr originally - now is arial 303 | %\newfont{\subttlit}{ariali at 14pt} % 13 Jan 00 gkmt 304 | %\newfont{\subttlbf}{arialbd at 14pt} % 13 Jan 00 gkmt 305 | %\newfont{\aufnt}{arial at 12pt} % was arialr originally - now is arial 306 | %\newfont{\auit}{ariali at 12pt} % 13 Jan 00 gkmt 307 | %\newfont{\affaddr}{arial at 10pt} % was arialr originally - now is arial 308 | %\newfont{\affaddrit}{ariali at 10pt} %13 Jan 00 gkmt 309 | %\newfont{\eaddfnt}{arial at 12pt} % was arialr originally - now is arial 310 | %\newfont{\ixpt}{times at 9pt} % was timenrr originally - now is times 311 | %\newfont{\confname}{timesi at 8pt} % was timenrri - now is timesi 312 | %\newfont{\crnotice}{times at 8pt} % was timenrr originally - now is times 313 | %\newfont{\ninept}{times at 9pt} % was timenrr originally - now is times 314 | 315 | % ********************************************* 316 | % -- End of block A -- 317 | % 318 | % 319 | % -- Start of block B -- UPDATED FONT NAMES 320 | % ********************************************* 321 | % Gerry Murray 11/30/2006 322 | % ********************************************* 323 | \newfont{\secfnt}{ptmb8t at 12pt} 324 | \newfont{\secit}{ptmbi8t at 12pt} %13 Jan 00 gkmt 325 | \newfont{\subsecfnt}{ptmri8t at 11pt} 326 | \newfont{\subsecit}{ptmbi8t at 11pt} % 327 | \newfont{\ttlfnt}{phvb8t at 18pt} 328 | \newfont{\ttlit}{phvbo8t at 18pt} % GM 2/4/2000 329 | \newfont{\subttlfnt}{phvr8t at 14pt} 330 | \newfont{\subttlit}{phvro8t at 14pt} % GM 2/4/2000 331 | \newfont{\subttlbf}{phvb8t at 14pt} % 13 Jan 00 gkmt 332 | \newfont{\aufnt}{phvr8t at 12pt} 333 | \newfont{\auit}{phvro8t at 12pt} % GM 2/4/2000 334 | \newfont{\affaddr}{phvr8t at 10pt} 335 | \newfont{\affaddrit}{phvro8t at 10pt} % GM 2/4/2000 336 | \newfont{\eaddfnt}{phvr8t at 12pt} 337 | \newfont{\ixpt}{ptmr8t at 9pt} 338 | \newfont{\confname}{ptmri8t at 8pt} 339 | \newfont{\crnotice}{ptmr8t at 8pt} 340 | \newfont{\ninept}{ptmr8t at 9pt} 341 | % +++++++++++++++++++++++++++++++++++++++++++++ 342 | % -- End of block B -- 343 | 344 | %\def\email#1{{{\eaddfnt{\vskip 4pt#1}}}} 345 | % If we have an email, inside a "shared affiliation" then we need the following instead 346 | \def\email#1{{{\eaddfnt{\par #1}}}} % revised - GM - 11/30/2006 347 | 348 | \def\addauthorsection{\ifnum\originalaucount>6 % was 3 - Gerry March 2007 349 | \section{Additional Authors}\the\addauthors 350 | \fi} 351 | 352 | \newcount\savesection 353 | \newcount\sectioncntr 354 | \global\sectioncntr=1 355 | 356 | \setcounter{secnumdepth}{3} 357 | 358 | \def\appendix{\par 359 | \section*{APPENDIX} 360 | \setcounter{section}{0} 361 | \setcounter{subsection}{0} 362 | \def\thesection{\Alph{section}} } 363 | 364 | \leftmargini 22.5pt 365 | \leftmarginii 19.8pt % > \labelsep + width of '(m)' 366 | \leftmarginiii 16.8pt % > \labelsep + width of 'vii.' 367 | \leftmarginiv 15.3pt % > \labelsep + width of 'M.' 368 | \leftmarginv 9pt 369 | \leftmarginvi 9pt 370 | 371 | \leftmargin\leftmargini 372 | \labelsep 4.5pt 373 | \labelwidth\leftmargini\advance\labelwidth-\labelsep 374 | 375 | \def\@listI{\leftmargin\leftmargini \parsep 3.6pt plus 2pt minus 1pt% 376 | \topsep 7.2pt plus 2pt minus 4pt% 377 | \itemsep 3.6pt plus 2pt minus 1pt} 378 | 379 | \let\@listi\@listI 380 | \@listi 381 | 382 | \def\@listii{\leftmargin\leftmarginii 383 | \labelwidth\leftmarginii\advance\labelwidth-\labelsep 384 | \topsep 3.6pt plus 2pt minus 1pt 385 | \parsep 1.8pt plus 0.9pt minus 0.9pt 386 | \itemsep \parsep} 387 | 388 | \def\@listiii{\leftmargin\leftmarginiii 389 | \labelwidth\leftmarginiii\advance\labelwidth-\labelsep 390 | \topsep 1.8pt plus 0.9pt minus 0.9pt 391 | \parsep \z@ \partopsep 1pt plus 0pt minus 1pt 392 | \itemsep \topsep} 393 | 394 | \def\@listiv{\leftmargin\leftmarginiv 395 | \labelwidth\leftmarginiv\advance\labelwidth-\labelsep} 396 | 397 | \def\@listv{\leftmargin\leftmarginv 398 | \labelwidth\leftmarginv\advance\labelwidth-\labelsep} 399 | 400 | \def\@listvi{\leftmargin\leftmarginvi 401 | \labelwidth\leftmarginvi\advance\labelwidth-\labelsep} 402 | 403 | \def\labelenumi{\theenumi.} 404 | \def\theenumi{\arabic{enumi}} 405 | 406 | \def\labelenumii{(\theenumii)} 407 | \def\theenumii{\alph{enumii}} 408 | \def\p@enumii{\theenumi} 409 | 410 | \def\labelenumiii{\theenumiii.} 411 | \def\theenumiii{\roman{enumiii}} 412 | \def\p@enumiii{\theenumi(\theenumii)} 413 | 414 | \def\labelenumiv{\theenumiv.} 415 | \def\theenumiv{\Alph{enumiv}} 416 | \def\p@enumiv{\p@enumiii\theenumiii} 417 | 418 | \def\labelitemi{$\bullet$} 419 | \def\labelitemii{\bf --} 420 | \def\labelitemiii{$\ast$} 421 | \def\labelitemiv{$\cdot$} 422 | 423 | \def\verse{\let\\=\@centercr 424 | \list{}{\itemsep\z@ \itemindent -1.5em\listparindent \itemindent 425 | \rightmargin\leftmargin\advance\leftmargin 1.5em}\item[]} 426 | \let\endverse\endlist 427 | 428 | \def\quotation{\list{}{\listparindent 1.5em 429 | \itemindent\listparindent 430 | \rightmargin\leftmargin \parsep 0pt plus 1pt}\item[]} 431 | \let\endquotation=\endlist 432 | 433 | \def\quote{\list{}{\rightmargin\leftmargin}\item[]} 434 | \let\endquote=\endlist 435 | 436 | \def\descriptionlabel#1{\hspace\labelsep \bf #1} 437 | \def\description{\list{}{\labelwidth\z@ \itemindent-\leftmargin 438 | \let\makelabel\descriptionlabel}} 439 | 440 | \let\enddescription\endlist 441 | 442 | \def\theequation{\arabic{equation}} 443 | 444 | \arraycolsep 4.5pt % Half the space between columns in an array environment. 445 | \tabcolsep 5.4pt % Half the space between columns in a tabular environment. 446 | \arrayrulewidth .5pt % Width of rules in array and tabular environment. % (was .4) updated Gerry March 20 2007 447 | \doublerulesep 1.8pt % Space between adjacent rules in array or tabular env. 448 | 449 | \tabbingsep \labelsep % Space used by the \' command. (See LaTeX manual.) 450 | 451 | \skip\@mpfootins =\skip\footins 452 | 453 | \fboxsep =2.7pt % Space left between box and text by \fbox and \framebox. 454 | \fboxrule =.5pt % Width of rules in box made by \fbox and \framebox. % (was .4) updated Gerry March 20 2007 455 | 456 | \def\thepart{\Roman{part}} % Roman numeral part numbers. 457 | \def\thesection {\arabic{section}} 458 | \def\thesubsection {\thesection.\arabic{subsection}} 459 | %\def\thesubsubsection {\thesubsection.\arabic{subsubsection}} % GM 7/30/2002 460 | %\def\theparagraph {\thesubsubsection.\arabic{paragraph}} % GM 7/30/2002 461 | \def\thesubparagraph {\theparagraph.\arabic{subparagraph}} 462 | 463 | \def\@pnumwidth{1.55em} 464 | \def\@tocrmarg {2.55em} 465 | \def\@dotsep{4.5} 466 | \setcounter{tocdepth}{3} 467 | 468 | %\def\tableofcontents{\@latexerr{\tableofcontents: Tables of contents are not 469 | % allowed in the `acmconf' document style.}\@eha} 470 | 471 | \def\tableofcontents{\ClassError{% 472 | \string\tableofcontents\space is not allowed in the `acmconf' document % January 2008 473 | style}\@eha} 474 | 475 | \def\l@part#1#2{\addpenalty{\@secpenalty} 476 | \addvspace{2.25em plus 1pt} % space above part line 477 | \begingroup 478 | \@tempdima 3em % width of box holding part number, used by 479 | \parindent \z@ \rightskip \@pnumwidth %% \numberline 480 | \parfillskip -\@pnumwidth 481 | {\large \bf % set line in \large boldface 482 | \leavevmode % TeX command to enter horizontal mode. 483 | #1\hfil \hbox to\@pnumwidth{\hss #2}}\par 484 | \nobreak % Never break after part entry 485 | \endgroup} 486 | 487 | \def\l@section#1#2{\addpenalty{\@secpenalty} % good place for page break 488 | \addvspace{1.0em plus 1pt} % space above toc entry 489 | \@tempdima 1.5em % width of box holding section number 490 | \begingroup 491 | \parindent \z@ \rightskip \@pnumwidth 492 | \parfillskip -\@pnumwidth 493 | \bf % Boldface. 494 | \leavevmode % TeX command to enter horizontal mode. 495 | \advance\leftskip\@tempdima %% added 5 Feb 88 to conform to 496 | \hskip -\leftskip %% 25 Jan 88 change to \numberline 497 | #1\nobreak\hfil \nobreak\hbox to\@pnumwidth{\hss #2}\par 498 | \endgroup} 499 | 500 | 501 | \def\l@subsection{\@dottedtocline{2}{1.5em}{2.3em}} 502 | \def\l@subsubsection{\@dottedtocline{3}{3.8em}{3.2em}} 503 | \def\l@paragraph{\@dottedtocline{4}{7.0em}{4.1em}} 504 | \def\l@subparagraph{\@dottedtocline{5}{10em}{5em}} 505 | 506 | %\def\listoffigures{\@latexerr{\listoffigures: Lists of figures are not 507 | % allowed in the `acmconf' document style.}\@eha} 508 | 509 | \def\listoffigures{\ClassError{% 510 | \string\listoffigures\space is not allowed in the `acmconf' document % January 2008 511 | style}\@eha} 512 | 513 | \def\l@figure{\@dottedtocline{1}{1.5em}{2.3em}} 514 | 515 | %\def\listoftables{\@latexerr{\listoftables: Lists of tables are not 516 | % allowed in the `acmconf' document style.}\@eha} 517 | %\let\l@table\l@figure 518 | 519 | \def\listoftables{\ClassError{% 520 | \string\listoftables\space is not allowed in the `acmconf' document % January 2008 521 | style}\@eha} 522 | \let\l@table\l@figure 523 | 524 | \def\footnoterule{\kern-3\p@ 525 | \hrule width .5\columnwidth % (was .4) updated Gerry March 20 2007 526 | \kern 2.6\p@} % The \hrule has default height of .4pt % (was .4) updated Gerry March 20 2007 527 | % ------ 528 | \long\def\@makefntext#1{\noindent 529 | %\hbox to .5em{\hss$^{\@thefnmark}$}#1} % original 530 | \hbox to .5em{\hss\textsuperscript{\@thefnmark}}#1} % C. Clifton / GM Oct. 2nd. 2002 531 | % ------- 532 | 533 | \long\def\@maketntext#1{\noindent 534 | #1} 535 | 536 | \long\def\@maketitlenotetext#1#2{\noindent 537 | \hbox to 1.8em{\hss$^{#1}$}#2} 538 | 539 | \setcounter{topnumber}{2} 540 | \def\topfraction{.7} 541 | \setcounter{bottomnumber}{1} 542 | \def\bottomfraction{.3} 543 | \setcounter{totalnumber}{3} 544 | \def\textfraction{.2} 545 | \def\floatpagefraction{.5} 546 | \setcounter{dbltopnumber}{2} 547 | \def\dbltopfraction{.7} 548 | \def\dblfloatpagefraction{.5} 549 | 550 | % 551 | \long\def\@makecaption#1#2{ 552 | \vskip \baselineskip 553 | \setbox\@tempboxa\hbox{\textbf{#1: #2}} 554 | \ifdim \wd\@tempboxa >\hsize % IF longer than one line: 555 | \textbf{#1: #2}\par % THEN set as ordinary paragraph. 556 | \else % ELSE center. 557 | \hbox to\hsize{\hfil\box\@tempboxa\hfil}\par 558 | \fi} 559 | 560 | % 561 | 562 | \long\def\@makecaption#1#2{ 563 | \vskip 10pt 564 | \setbox\@tempboxa\hbox{\textbf{#1: #2}} 565 | \ifdim \wd\@tempboxa >\hsize % IF longer than one line: 566 | \textbf{#1: #2}\par % THEN set as ordinary paragraph. 567 | \else % ELSE center. 568 | \hbox to\hsize{\hfil\box\@tempboxa\hfil} 569 | \fi} 570 | 571 | \@ifundefined{figure}{\newcounter {figure}} % this is for LaTeX2e 572 | 573 | \def\fps@figure{tbp} 574 | \def\ftype@figure{1} 575 | \def\ext@figure{lof} 576 | \def\fnum@figure{Figure \thefigure} 577 | \def\figure{\@float{figure}} 578 | %\let\endfigure\end@float 579 | \def\endfigure{\end@float} % Gerry January 2008 580 | \@namedef{figure*}{\@dblfloat{figure}} 581 | \@namedef{endfigure*}{\end@dblfloat} 582 | 583 | \@ifundefined{table}{\newcounter {table}} % this is for LaTeX2e 584 | 585 | \def\fps@table{tbp} 586 | \def\ftype@table{2} 587 | \def\ext@table{lot} 588 | \def\fnum@table{Table \thetable} 589 | \def\table{\@float{table}} 590 | %\let\endtable\end@float 591 | \def\endtable{\end@float} % Gerry January 2008 592 | \@namedef{table*}{\@dblfloat{table}} 593 | \@namedef{endtable*}{\end@dblfloat} 594 | 595 | \newtoks\titleboxnotes 596 | \newcount\titleboxnoteflag 597 | 598 | \def\maketitle{\par 599 | \begingroup 600 | \def\thefootnote{\fnsymbol{footnote}} 601 | \def\@makefnmark{\hbox 602 | to 0pt{$^{\@thefnmark}$\hss}} 603 | \twocolumn[\@maketitle] 604 | \@thanks 605 | \endgroup 606 | \setcounter{footnote}{0} 607 | \let\maketitle\relax 608 | \let\@maketitle\relax 609 | \gdef\@thanks{}\gdef\@author{}\gdef\@title{}\gdef\@subtitle{}\let\thanks\relax 610 | \@copyrightspace} 611 | 612 | %% CHANGES ON NEXT LINES 613 | \newif\if@ll % to record which version of LaTeX is in use 614 | 615 | \expandafter\ifx\csname LaTeXe\endcsname\relax % LaTeX2.09 is used 616 | \else% LaTeX2e is used, so set ll to true 617 | \global\@lltrue 618 | \fi 619 | 620 | \if@ll 621 | \NeedsTeXFormat{LaTeX2e} 622 | \ProvidesClass{sig-alternate} [2012/05/23 - V2.5 - based on acmproc.cls V1.3 ] 623 | \RequirePackage{latexsym}% QUERY: are these two really needed? 624 | \let\dooptions\ProcessOptions 625 | \else 626 | \let\dooptions\@options 627 | \fi 628 | %% END CHANGES 629 | 630 | \def\@height{height} 631 | \def\@width{width} 632 | \def\@minus{minus} 633 | \def\@plus{plus} 634 | \def\hb@xt@{\hbox to} 635 | \newif\if@faircopy 636 | \@faircopyfalse 637 | \def\ds@faircopy{\@faircopytrue} 638 | 639 | \def\ds@preprint{\@faircopyfalse} 640 | 641 | \@twosidetrue 642 | \@mparswitchtrue 643 | \def\ds@draft{\overfullrule 5\p@} 644 | %% CHANGE ON NEXT LINE 645 | \dooptions 646 | 647 | \lineskip \p@ 648 | \normallineskip \p@ 649 | \def\baselinestretch{1} 650 | \def\@ptsize{0} %needed for amssymbols.sty 651 | 652 | %% CHANGES ON NEXT LINES 653 | \if@ll% allow use of old-style font change commands in LaTeX2e 654 | \@maxdepth\maxdepth 655 | % 656 | \DeclareOldFontCommand{\rm}{\ninept\rmfamily}{\mathrm} 657 | \DeclareOldFontCommand{\sf}{\normalfont\sffamily}{\mathsf} 658 | \DeclareOldFontCommand{\tt}{\normalfont\ttfamily}{\mathtt} 659 | \DeclareOldFontCommand{\bf}{\normalfont\bfseries}{\mathbf} 660 | \DeclareOldFontCommand{\it}{\normalfont\itshape}{\mathit} 661 | \DeclareOldFontCommand{\sl}{\normalfont\slshape}{\@nomath\sl} 662 | \DeclareOldFontCommand{\sc}{\normalfont\scshape}{\@nomath\sc} 663 | \DeclareRobustCommand*{\cal}{\@fontswitch{\relax}{\mathcal}} 664 | \DeclareRobustCommand*{\mit}{\@fontswitch{\relax}{\mathnormal}} 665 | \fi 666 | % 667 | \if@ll 668 | \renewcommand{\rmdefault}{cmr} % was 'ttm' 669 | % Note! I have also found 'mvr' to work ESPECIALLY well. 670 | % Gerry - October 1999 671 | % You may need to change your LV1times.fd file so that sc is 672 | % mapped to cmcsc - -for smallcaps -- that is if you decide 673 | % to change {cmr} to {times} above. (Not recommended) 674 | \renewcommand{\@ptsize}{} 675 | \renewcommand{\normalsize}{% 676 | %\@setfontsize\normalsize\@ixpt{10.5\p@}%\ninept% 677 | \@setfontsize\normalsize\@xpt{11\p@}%\tenpt% %% Adjusted for 10pt 678 | \abovedisplayskip 6\p@ \@plus2\p@ \@minus\p@ 679 | \belowdisplayskip \abovedisplayskip 680 | \abovedisplayshortskip 6\p@ \@minus 3\p@ 681 | \belowdisplayshortskip 6\p@ \@minus 3\p@ 682 | \let\@listi\@listI 683 | } 684 | \else 685 | \def\@normalsize{%changed next to 9 from 10 686 | \@setsize\normalsize{10\p@}\ixpt\@ixpt 687 | \abovedisplayskip 6\p@ \@plus2\p@ \@minus\p@ 688 | \belowdisplayskip \abovedisplayskip 689 | \abovedisplayshortskip 6\p@ \@minus 3\p@ 690 | \belowdisplayshortskip 6\p@ \@minus 3\p@ 691 | \let\@listi\@listI 692 | }% 693 | \fi 694 | \if@ll 695 | \newcommand\scriptsize{\@setfontsize\scriptsize\@viipt{8\p@}} 696 | \newcommand\tiny{\@setfontsize\tiny\@vpt{6\p@}} 697 | \newcommand\large{\@setfontsize\large\@xiipt{14\p@}} 698 | \newcommand\Large{\@setfontsize\Large\@xivpt{18\p@}} 699 | \newcommand\LARGE{\@setfontsize\LARGE\@xviipt{20\p@}} 700 | \newcommand\huge{\@setfontsize\huge\@xxpt{25\p@}} 701 | \newcommand\Huge{\@setfontsize\Huge\@xxvpt{30\p@}} 702 | \else 703 | \def\scriptsize{\@setsize\scriptsize{8\p@}\viipt\@viipt} 704 | \def\tiny{\@setsize\tiny{6\p@}\vpt\@vpt} 705 | \def\large{\@setsize\large{14\p@}\xiipt\@xiipt} 706 | \def\Large{\@setsize\Large{18\p@}\xivpt\@xivpt} 707 | \def\LARGE{\@setsize\LARGE{20\p@}\xviipt\@xviipt} 708 | \def\huge{\@setsize\huge{25\p@}\xxpt\@xxpt} 709 | \def\Huge{\@setsize\Huge{30\p@}\xxvpt\@xxvpt} 710 | \fi 711 | \normalsize 712 | 713 | % make aubox hsize/number of authors up to 3, less gutter 714 | % then showbox gutter showbox gutter showbox -- GKMT Aug 99 715 | \newbox\@acmtitlebox 716 | \def\@maketitle{\newpage 717 | \null 718 | \setbox\@acmtitlebox\vbox{% 719 | \baselineskip 10pt 720 | \vskip 1em % Vertical space above title. 721 | \begin{center} 722 | {\ttlfnt \@title\par} % Title set in 18pt Helvetica (Arial) bold size. 723 | \vskip 1em % Vertical space after title. 724 | %This should be the subtitle. 725 | {\subttlfnt \the\subtitletext\par}\vskip 1.25em%\fi 726 | {\baselineskip 16pt\aufnt % each author set in \12 pt Arial, in a 727 | \lineskip .5em % tabular environment 728 | \begin{tabular}[t]{c}\@author 729 | \end{tabular}\par} 730 | \vskip 2em % Vertical space after author. 731 | \end{center}} 732 | \dimen0=\ht\@acmtitlebox 733 | \advance\dimen0 by -12.75pc\relax % Increased space for title box -- KBT 734 | \unvbox\@acmtitlebox 735 | \ifdim\dimen0<0.0pt\relax\vskip-\dimen0\fi} 736 | 737 | 738 | \newcount\titlenotecount 739 | \global\titlenotecount=0 740 | \newtoks\tntoks 741 | \newtoks\tntokstwo 742 | \newtoks\tntoksthree 743 | \newtoks\tntoksfour 744 | \newtoks\tntoksfive 745 | 746 | \def\abstract{ 747 | \ifnum\titlenotecount>0 % was =1 748 | \insert\footins{% 749 | \reset@font\footnotesize 750 | \interlinepenalty\interfootnotelinepenalty 751 | \splittopskip\footnotesep 752 | \splitmaxdepth \dp\strutbox \floatingpenalty \@MM 753 | \hsize\columnwidth \@parboxrestore 754 | \protected@edef\@currentlabel{% 755 | }% 756 | \color@begingroup 757 | \ifnum\titlenotecount=1 758 | \@maketntext{% 759 | \raisebox{4pt}{$\ast$}\rule\z@\footnotesep\ignorespaces\the\tntoks\@finalstrut\strutbox}% 760 | \fi 761 | \ifnum\titlenotecount=2 762 | \@maketntext{% 763 | \raisebox{4pt}{$\ast$}\rule\z@\footnotesep\ignorespaces\the\tntoks\par\@finalstrut\strutbox}% 764 | \@maketntext{% 765 | \raisebox{4pt}{$\dagger$}\rule\z@\footnotesep\ignorespaces\the\tntokstwo\@finalstrut\strutbox}% 766 | \fi 767 | \ifnum\titlenotecount=3 768 | \@maketntext{% 769 | \raisebox{4pt}{$\ast$}\rule\z@\footnotesep\ignorespaces\the\tntoks\par\@finalstrut\strutbox}% 770 | \@maketntext{% 771 | \raisebox{4pt}{$\dagger$}\rule\z@\footnotesep\ignorespaces\the\tntokstwo\par\@finalstrut\strutbox}% 772 | \@maketntext{% 773 | \raisebox{4pt}{$\ddagger$}\rule\z@\footnotesep\ignorespaces\the\tntoksthree\@finalstrut\strutbox}% 774 | \fi 775 | \ifnum\titlenotecount=4 776 | \@maketntext{% 777 | \raisebox{4pt}{$\ast$}\rule\z@\footnotesep\ignorespaces\the\tntoks\par\@finalstrut\strutbox}% 778 | \@maketntext{% 779 | \raisebox{4pt}{$\dagger$}\rule\z@\footnotesep\ignorespaces\the\tntokstwo\par\@finalstrut\strutbox}% 780 | \@maketntext{% 781 | \raisebox{4pt}{$\ddagger$}\rule\z@\footnotesep\ignorespaces\the\tntoksthree\par\@finalstrut\strutbox}% 782 | \@maketntext{% 783 | \raisebox{4pt}{$\S$}\rule\z@\footnotesep\ignorespaces\the\tntoksfour\@finalstrut\strutbox}% 784 | \fi 785 | \ifnum\titlenotecount=5 786 | \@maketntext{% 787 | \raisebox{4pt}{$\ast$}\rule\z@\footnotesep\ignorespaces\the\tntoks\par\@finalstrut\strutbox}% 788 | \@maketntext{% 789 | \raisebox{4pt}{$\dagger$}\rule\z@\footnotesep\ignorespaces\the\tntokstwo\par\@finalstrut\strutbox}% 790 | \@maketntext{% 791 | \raisebox{4pt}{$\ddagger$}\rule\z@\footnotesep\ignorespaces\the\tntoksthree\par\@finalstrut\strutbox}% 792 | \@maketntext{% 793 | \raisebox{4pt}{$\S$}\rule\z@\footnotesep\ignorespaces\the\tntoksfour\par\@finalstrut\strutbox}% 794 | \@maketntext{% 795 | \raisebox{4pt}{$\P$}\rule\z@\footnotesep\ignorespaces\the\tntoksfive\@finalstrut\strutbox}% 796 | \fi 797 | \color@endgroup} %g} 798 | \fi 799 | \setcounter{footnote}{0} 800 | \section*{ABSTRACT}\normalsize%\ninept 801 | } 802 | 803 | \def\endabstract{\if@twocolumn\else\endquotation\fi} 804 | 805 | 806 | % \def\keywords{\if@twocolumn 807 | % \section*{Keywords} 808 | % \else \small 809 | % \quotation 810 | % \fi} 811 | 812 | 813 | \def\terms{\if@twocolumn 814 | \section*{General Terms} 815 | \else \small 816 | \quotation 817 | \fi} 818 | 819 | % -- Classification needs to be a bit smart due to optionals - Gerry/Georgia November 2nd. 1999 820 | \newcount\catcount 821 | \global\catcount=1 822 | 823 | \def\category#1#2#3{% 824 | \ifnum\catcount=1 825 | \section*{Categories and Subject Descriptors} 826 | \advance\catcount by 1\else{\unskip; }\fi 827 | \@ifnextchar [{\@category{#1}{#2}{#3}}{\@category{#1}{#2}{#3}[]}% 828 | } 829 | 830 | \def\@category#1#2#3[#4]{% 831 | \begingroup 832 | \let\and\relax 833 | #1 [\textbf{#2}]% 834 | \if!#4!% 835 | \if!#3!\else : #3\fi 836 | \else 837 | :\space 838 | \if!#3!\else #3\kern\z@---\hskip\z@\fi 839 | \textit{#4}% 840 | \fi 841 | \endgroup 842 | } 843 | % 844 | 845 | %%% This section (written by KBT) handles the 1" box in the lower left 846 | %%% corner of the left column of the first page by creating a picture, 847 | %%% and inserting the predefined string at the bottom (with a negative 848 | %%% displacement to offset the space allocated for a non-existent 849 | %%% caption). 850 | %%% 851 | \newtoks\copyrightnotice 852 | \def\ftype@copyrightbox{8} 853 | \def\@copyrightspace{ 854 | %\@float{copyrightbox}[b] 855 | %\begin{center} 856 | %\setlength{\unitlength}{1pc} 857 | %\begin{picture}(20,6) %Space for copyright notice 858 | %\put(0,-0.95){\crnotice{\@toappear}} 859 | %\end{picture} 860 | %\end{center} 861 | %\end@float 862 | } 863 | 864 | %\def\@toappear{} % Default setting blank - commands below change this. 865 | %\long\def\toappear#1{\def\@toappear{\parbox[b]{20pc}{\baselineskip 9pt%#1}}} 866 | %\def\toappearbox#1{\def\@toappear{\raisebox{5pt}{\framebox[20pc]{\parb%ox[b]{19pc}{#1}}}}} 867 | 868 | %\newtoks\conf 869 | %\newtoks\confinfo 870 | %\def\conferenceinfo#1#2{\global\conf={#1}\global\confinfo{#2}} 871 | 872 | 873 | %\def\marginpar{\@latexerr{The \marginpar command is not allowed in the 874 | % `acmconf' document style.}\@eha} 875 | 876 | \def\marginpar{\ClassError{% 877 | \string\marginpar\space is not allowed in the `acmconf' document % January 2008 878 | style}\@eha} 879 | 880 | \mark{{}{}} % Initializes TeX's marks 881 | 882 | \def\today{\ifcase\month\or 883 | January\or February\or March\or April\or May\or June\or 884 | July\or August\or September\or October\or November\or December\fi 885 | \space\number\day, \number\year} 886 | 887 | \def\@begintheorem#1#2{% 888 | \parskip 0pt % GM July 2000 (for tighter spacing) 889 | \trivlist 890 | \item[% 891 | \hskip 10\p@ 892 | \hskip \labelsep 893 | {{\sc #1}\hskip 5\p@\relax#2.}% 894 | ] 895 | \it 896 | } 897 | \def\@opargbegintheorem#1#2#3{% 898 | \parskip 0pt % GM July 2000 (for tighter spacing) 899 | \trivlist 900 | \item[% 901 | \hskip 10\p@ 902 | \hskip \labelsep 903 | {\sc #1\ #2\ % This mod by Gerry to enumerate corollaries 904 | \setbox\@tempboxa\hbox{(#3)} % and bracket the 'corollary title' 905 | \ifdim \wd\@tempboxa>\z@ % and retain the correct numbering of e.g. theorems 906 | \hskip 5\p@\relax % if they occur 'around' said corollaries. 907 | \box\@tempboxa % Gerry - Nov. 1999. 908 | \fi.}% 909 | ] 910 | \it 911 | } 912 | \newif\if@qeded 913 | \global\@qededfalse 914 | 915 | % -- original 916 | %\def\proof{% 917 | % \vspace{-\parskip} % GM July 2000 (for tighter spacing) 918 | % \global\@qededfalse 919 | % \@ifnextchar[{\@xproof}{\@proof}% 920 | %} 921 | % -- end of original 922 | 923 | % (JSS) Fix for vertical spacing bug - Gerry Murray July 30th. 2002 924 | \def\proof{% 925 | \vspace{-\lastskip}\vspace{-\parsep}\penalty-51% 926 | \global\@qededfalse 927 | \@ifnextchar[{\@xproof}{\@proof}% 928 | } 929 | 930 | \def\endproof{% 931 | \if@qeded\else\qed\fi 932 | \endtrivlist 933 | } 934 | \def\@proof{% 935 | \trivlist 936 | \item[% 937 | \hskip 10\p@ 938 | \hskip \labelsep 939 | {\sc Proof.}% 940 | ] 941 | \ignorespaces 942 | } 943 | \def\@xproof[#1]{% 944 | \trivlist 945 | \item[\hskip 10\p@\hskip \labelsep{\sc Proof #1.}]% 946 | \ignorespaces 947 | } 948 | \def\qed{% 949 | \unskip 950 | \kern 10\p@ 951 | \begingroup 952 | \unitlength\p@ 953 | \linethickness{.4\p@}% 954 | \framebox(6,6){}% 955 | \endgroup 956 | \global\@qededtrue 957 | } 958 | 959 | \def\newdef#1#2{% 960 | \expandafter\@ifdefinable\csname #1\endcsname 961 | {\@definecounter{#1}% 962 | \expandafter\xdef\csname the#1\endcsname{\@thmcounter{#1}}% 963 | \global\@namedef{#1}{\@defthm{#1}{#2}}% 964 | \global\@namedef{end#1}{\@endtheorem}% 965 | }% 966 | } 967 | \def\@defthm#1#2{% 968 | \refstepcounter{#1}% 969 | \@ifnextchar[{\@ydefthm{#1}{#2}}{\@xdefthm{#1}{#2}}% 970 | } 971 | \def\@xdefthm#1#2{% 972 | \@begindef{#2}{\csname the#1\endcsname}% 973 | \ignorespaces 974 | } 975 | \def\@ydefthm#1#2[#3]{% 976 | \trivlist 977 | \item[% 978 | \hskip 10\p@ 979 | \hskip \labelsep 980 | {\it #2% 981 | % \savebox\@tempboxa{#3}% 982 | \saveb@x\@tempboxa{#3}% % January 2008 983 | \ifdim \wd\@tempboxa>\z@ 984 | \ \box\@tempboxa 985 | \fi.% 986 | }]% 987 | \ignorespaces 988 | } 989 | \def\@begindef#1#2{% 990 | \trivlist 991 | \item[% 992 | \hskip 10\p@ 993 | \hskip \labelsep 994 | {\it #1\ \rm #2.}% 995 | ]% 996 | } 997 | \def\theequation{\arabic{equation}} 998 | 999 | \newcounter{part} 1000 | \newcounter{section} 1001 | \newcounter{subsection}[section] 1002 | \newcounter{subsubsection}[subsection] 1003 | \newcounter{paragraph}[subsubsection] 1004 | \def\thepart{\Roman{part}} 1005 | \def\thesection{\arabic{section}} 1006 | \def\thesubsection{\thesection.\arabic{subsection}} 1007 | \def\thesubsubsection{\thesubsection.\arabic{subsubsection}} %removed \subsecfnt 29 July 2002 gkmt 1008 | \def\theparagraph{\thesubsubsection.\arabic{paragraph}} %removed \subsecfnt 29 July 2002 gkmt 1009 | \newif\if@uchead 1010 | \@ucheadfalse 1011 | 1012 | %% CHANGES: NEW NOTE 1013 | %% NOTE: OK to use old-style font commands below, since they were 1014 | %% suitably redefined for LaTeX2e 1015 | %% END CHANGES 1016 | \setcounter{secnumdepth}{3} 1017 | \def\part{% 1018 | \@startsection{part}{9}{\z@}{-10\p@ \@plus -4\p@ \@minus -2\p@} 1019 | {4\p@}{\normalsize\@ucheadtrue}% 1020 | } 1021 | \def\section{% 1022 | \@startsection{section}{1}{\z@}{-10\p@ \@plus -4\p@ \@minus -2\p@}% GM 1023 | {4\p@}{\baselineskip 14pt\secfnt\@ucheadtrue}% 1024 | } 1025 | 1026 | \def\subsection{% 1027 | \@startsection{subsection}{2}{\z@}{-8\p@ \@plus -2\p@ \@minus -\p@} 1028 | {4\p@}{\secfnt}% 1029 | } 1030 | \def\subsubsection{% 1031 | \@startsection{subsubsection}{3}{\z@}{-8\p@ \@plus -2\p@ \@minus -\p@}% 1032 | {4\p@}{\subsecfnt}% 1033 | } 1034 | %\def\paragraph{% 1035 | % \vskip 12pt\@startsection{paragraph}{3}{\z@}{6\p@ \@plus \p@}% original 1036 | % {-5\p@}{\subsecfnt}% 1037 | %} 1038 | % If one wants sections, subsections and subsubsections numbered, 1039 | % but not paragraphs, one usually sets secnumepth to 3. 1040 | % For that, the "depth" of paragraphs must be given correctly 1041 | % in the definition (``4'' instead of ``3'' as second argument 1042 | % of @startsection): 1043 | \def\paragraph{% 1044 | \vskip 12pt\@startsection{paragraph}{4}{\z@}{6\p@ \@plus \p@}% % GM and Wolfgang May - 11/30/06 1045 | {-5\p@}{\subsecfnt}% 1046 | } 1047 | \let\@period=. 1048 | \def\@startsection#1#2#3#4#5#6{% 1049 | \if@noskipsec %gkmt, 11 aug 99 1050 | \global\let\@period\@empty 1051 | \leavevmode 1052 | \global\let\@period.% 1053 | \fi 1054 | \par % 1055 | \@tempskipa #4\relax 1056 | \@afterindenttrue 1057 | \ifdim \@tempskipa <\z@ 1058 | \@tempskipa -\@tempskipa 1059 | \@afterindentfalse 1060 | \fi 1061 | \if@nobreak 1062 | \everypar{}% 1063 | \else 1064 | \addpenalty\@secpenalty 1065 | \addvspace\@tempskipa 1066 | \fi 1067 | \parskip=0pt % GM July 2000 (non numbered) section heads 1068 | \@ifstar 1069 | {\@ssect{#3}{#4}{#5}{#6}} 1070 | {\@dblarg{\@sect{#1}{#2}{#3}{#4}{#5}{#6}}}% 1071 | } 1072 | \def\@sect#1#2#3#4#5#6[#7]#8{% 1073 | \ifnum #2>\c@secnumdepth 1074 | \let\@svsec\@empty 1075 | \else 1076 | \refstepcounter{#1}% 1077 | \edef\@svsec{% 1078 | \begingroup 1079 | %\ifnum#2>2 \noexpand\rm \fi % changed to next 29 July 2002 gkmt 1080 | \ifnum#2>2 \noexpand#6 \fi 1081 | \csname the#1\endcsname 1082 | \endgroup 1083 | \ifnum #2=1\relax .\fi 1084 | \hskip 1em 1085 | }% 1086 | \fi 1087 | \@tempskipa #5\relax 1088 | \ifdim \@tempskipa>\z@ 1089 | \begingroup 1090 | #6\relax 1091 | \@hangfrom{\hskip #3\relax\@svsec}% 1092 | \begingroup 1093 | \interlinepenalty \@M 1094 | \if@uchead 1095 | \uppercase{#8}% 1096 | \else 1097 | #8% 1098 | \fi 1099 | \par 1100 | \endgroup 1101 | \endgroup 1102 | \csname #1mark\endcsname{#7}% 1103 | \vskip -12pt %gkmt, 11 aug 99 and GM July 2000 (was -14) - numbered section head spacing 1104 | \addcontentsline{toc}{#1}{% 1105 | \ifnum #2>\c@secnumdepth \else 1106 | \protect\numberline{\csname the#1\endcsname}% 1107 | \fi 1108 | #7% 1109 | }% 1110 | \else 1111 | \def\@svsechd{% 1112 | #6% 1113 | \hskip #3\relax 1114 | \@svsec 1115 | \if@uchead 1116 | \uppercase{#8}% 1117 | \else 1118 | #8% 1119 | \fi 1120 | \csname #1mark\endcsname{#7}% 1121 | \addcontentsline{toc}{#1}{% 1122 | \ifnum #2>\c@secnumdepth \else 1123 | \protect\numberline{\csname the#1\endcsname}% 1124 | \fi 1125 | #7% 1126 | }% 1127 | }% 1128 | \fi 1129 | \@xsect{#5}\hskip 1pt 1130 | \par 1131 | } 1132 | \def\@xsect#1{% 1133 | \@tempskipa #1\relax 1134 | \ifdim \@tempskipa>\z@ 1135 | \par 1136 | \nobreak 1137 | \vskip \@tempskipa 1138 | \@afterheading 1139 | \else 1140 | \global\@nobreakfalse 1141 | \global\@noskipsectrue 1142 | \everypar{% 1143 | \if@noskipsec 1144 | \global\@noskipsecfalse 1145 | \clubpenalty\@M 1146 | \hskip -\parindent 1147 | \begingroup 1148 | \@svsechd 1149 | \@period 1150 | \endgroup 1151 | \unskip 1152 | \@tempskipa #1\relax 1153 | \hskip -\@tempskipa 1154 | \else 1155 | \clubpenalty \@clubpenalty 1156 | \everypar{}% 1157 | \fi 1158 | }% 1159 | \fi 1160 | \ignorespaces 1161 | } 1162 | \def\@trivlist{% 1163 | \@topsepadd\topsep 1164 | \if@noskipsec 1165 | \global\let\@period\@empty 1166 | \leavevmode 1167 | \global\let\@period.% 1168 | \fi 1169 | \ifvmode 1170 | \advance\@topsepadd\partopsep 1171 | \else 1172 | \unskip 1173 | \par 1174 | \fi 1175 | \if@inlabel 1176 | \@noparitemtrue 1177 | \@noparlisttrue 1178 | \else 1179 | \@noparlistfalse 1180 | \@topsep\@topsepadd 1181 | \fi 1182 | \advance\@topsep \parskip 1183 | \leftskip\z@skip 1184 | \rightskip\@rightskip 1185 | \parfillskip\@flushglue 1186 | \@setpar{\if@newlist\else{\@@par}\fi} 1187 | \global\@newlisttrue 1188 | \@outerparskip\parskip 1189 | } 1190 | 1191 | %%% Actually, 'abbrev' works just fine as the default 1192 | %%% Bibliography style. 1193 | 1194 | \typeout{Using 'Abbrev' bibliography style} 1195 | \newcommand\bibyear[2]{% 1196 | \unskip\quad\ignorespaces#1\unskip 1197 | \if#2..\quad \else \quad#2 \fi 1198 | } 1199 | \newcommand{\bibemph}[1]{{\em#1}} 1200 | \newcommand{\bibemphic}[1]{{\em#1\/}} 1201 | \newcommand{\bibsc}[1]{{\sc#1}} 1202 | \def\@normalcite{% 1203 | \def\@cite##1##2{[##1\if@tempswa , ##2\fi]}% 1204 | } 1205 | \def\@citeNB{% 1206 | \def\@cite##1##2{##1\if@tempswa , ##2\fi}% 1207 | } 1208 | \def\@citeRB{% 1209 | \def\@cite##1##2{##1\if@tempswa , ##2\fi]}% 1210 | } 1211 | \def\start@cite#1#2{% 1212 | \edef\citeauthoryear##1##2##3{% 1213 | ###1% 1214 | \ifnum#2=\z@ \else\ ###2\fi 1215 | }% 1216 | \ifnum#1=\thr@@ 1217 | \let\@@cite\@citeyear 1218 | \else 1219 | \let\@@cite\@citenormal 1220 | \fi 1221 | \@ifstar{\@citeNB\@@cite}{\@normalcite\@@cite}% 1222 | } 1223 | %\def\cite{\start@cite23} 1224 | \DeclareRobustCommand\cite{\start@cite23} % January 2008 1225 | \def\citeNP{\cite*} % No Parentheses e.g. 5 1226 | %\def\citeA{\start@cite10} 1227 | \DeclareRobustCommand\citeA{\start@cite10} % January 2008 1228 | \def\citeANP{\citeA*} 1229 | %\def\shortcite{\start@cite23} 1230 | \DeclareRobustCommand\shortcite{\start@cite23} % January 2008 1231 | \def\shortciteNP{\shortcite*} 1232 | %\def\shortciteA{\start@cite20} 1233 | \DeclareRobustCommand\shortciteA{\start@cite20} % January 2008 1234 | \def\shortciteANP{\shortciteA*} 1235 | %\def\citeyear{\start@cite30} 1236 | \DeclareRobustCommand\citeyear{\start@cite30} % January 2008 1237 | \def\citeyearNP{\citeyear*} 1238 | %\def\citeN{% 1239 | \DeclareRobustCommand\citeN{% % January 2008 1240 | \@citeRB 1241 | \def\citeauthoryear##1##2##3{##1\ [##3% 1242 | \def\reserved@a{##1}% 1243 | \def\citeauthoryear####1####2####3{% 1244 | \def\reserved@b{####1}% 1245 | \ifx\reserved@a\reserved@b 1246 | ####3% 1247 | \else 1248 | \errmessage{Package acmart Error: author mismatch 1249 | in \string\citeN^^J^^J% 1250 | See the acmart package documentation for explanation}% 1251 | \fi 1252 | }% 1253 | }% 1254 | \@ifstar\@citeyear\@citeyear 1255 | } 1256 | %\def\shortciteN{% 1257 | \DeclareRobustCommand\shortciteN{% % January 2008 1258 | \@citeRB 1259 | \def\citeauthoryear##1##2##3{##2\ [##3% 1260 | \def\reserved@a{##2}% 1261 | \def\citeauthoryear####1####2####3{% 1262 | \def\reserved@b{####2}% 1263 | \ifx\reserved@a\reserved@b 1264 | ####3% 1265 | \else 1266 | \errmessage{Package acmart Error: author mismatch 1267 | in \string\shortciteN^^J^^J% 1268 | See the acmart package documentation for explanation}% 1269 | \fi 1270 | }% 1271 | }% 1272 | \@ifstar\@citeyear\@citeyear % GM July 2000 1273 | } 1274 | 1275 | \def\@citenormal{% 1276 | \@ifnextchar [{\@tempswatrue\@citex;}% 1277 | % original {\@tempswafalse\@citex,[]}% was ; Gerry 2/24/00 1278 | {\@tempswafalse\@citex[]}% % GERRY FIX FOR BABEL 3/20/2009 1279 | } 1280 | 1281 | \def\@citeyear{% 1282 | \@ifnextchar [{\@tempswatrue\@citex,}% 1283 | % original {\@tempswafalse\@citex,[]}% 1284 | {\@tempswafalse\@citex[]}% % GERRY FIX FOR BABEL 3/20/2009 1285 | } 1286 | 1287 | \def\@citex#1[#2]#3{% 1288 | \let\@citea\@empty 1289 | \@cite{% 1290 | \@for\@citeb:=#3\do{% 1291 | \@citea 1292 | % original \def\@citea{#1 }% 1293 | \def\@citea{#1, }% % GERRY FIX FOR BABEL 3/20/2009 -- SO THAT YOU GET [1, 2] IN THE BODY TEXT 1294 | \edef\@citeb{\expandafter\@iden\@citeb}% 1295 | \if@filesw 1296 | \immediate\write\@auxout{\string\citation{\@citeb}}% 1297 | \fi 1298 | \@ifundefined{b@\@citeb}{% 1299 | {\bf ?}% 1300 | \@warning{% 1301 | Citation `\@citeb' on page \thepage\space undefined% 1302 | }% 1303 | }% 1304 | {\csname b@\@citeb\endcsname}% 1305 | }% 1306 | }{#2}% 1307 | } 1308 | %\let\@biblabel\@gobble % Dec. 2008 - Gerry 1309 | % ---- 1310 | \def\@biblabelnum#1{[#1]} % Gerry's solution #1 - for Natbib -- April 2009 1311 | \let\@biblabel=\@biblabelnum % Gerry's solution #1 - for Natbib -- April 2009 1312 | \def\newblock{\relax} % Gerry Dec. 2008 1313 | % --- 1314 | \newdimen\bibindent 1315 | \setcounter{enumi}{1} 1316 | \bibindent=0em 1317 | \def\thebibliography#1{% 1318 | \ifnum\addauflag=0\addauthorsection\global\addauflag=1\fi 1319 | \section[References]{% <=== OPTIONAL ARGUMENT ADDED HERE 1320 | {References} % was uppercased but this affects pdf bookmarks (SP/GM October 2004) 1321 | {\vskip -2pt plus 1pt} % GM Nov. 2006 / GM July 2000 (for somewhat tighter spacing) 1322 | \@mkboth{{\refname}}{{\refname}}% 1323 | }% 1324 | \refsmall 1325 | \list{[\arabic{enumi}]}{% 1326 | \settowidth\labelwidth{[#1]}% 1327 | \leftmargin\labelwidth 1328 | \advance\leftmargin\labelsep 1329 | \advance\leftmargin\bibindent 1330 | \parsep=0pt\itemsep=5pt % GM July 2000 1331 | \itemindent -\bibindent 1332 | \listparindent \itemindent 1333 | \usecounter{enumi} 1334 | }% 1335 | \let\newblock\@empty 1336 | \raggedright % GM July 2000 1337 | \sloppy 1338 | \sfcode`\.=1000\relax 1339 | } 1340 | 1341 | 1342 | \gdef\balancecolumns 1343 | {\vfill\eject 1344 | \global\@colht=\textheight 1345 | \global\ht\@cclv=\textheight 1346 | } 1347 | 1348 | \newcount\colcntr 1349 | \global\colcntr=0 1350 | %\newbox\savebox 1351 | \newbox\saveb@x % January 2008 1352 | 1353 | \gdef \@makecol {% 1354 | \global\advance\colcntr by 1 1355 | \ifnum\colcntr>2 \global\colcntr=1\fi 1356 | \ifvoid\footins 1357 | \setbox\@outputbox \box\@cclv 1358 | \else 1359 | \setbox\@outputbox \vbox{% 1360 | \boxmaxdepth \@maxdepth 1361 | \@tempdima\dp\@cclv 1362 | \unvbox \@cclv 1363 | \vskip-\@tempdima 1364 | \vskip \skip\footins 1365 | \color@begingroup 1366 | \normalcolor 1367 | \footnoterule 1368 | \unvbox \footins 1369 | \color@endgroup 1370 | }% 1371 | \fi 1372 | \xdef\@freelist{\@freelist\@midlist}% 1373 | \global \let \@midlist \@empty 1374 | \@combinefloats 1375 | \ifvbox\@kludgeins 1376 | \@makespecialcolbox 1377 | \else 1378 | \setbox\@outputbox \vbox to\@colht {% 1379 | \@texttop 1380 | \dimen@ \dp\@outputbox 1381 | \unvbox \@outputbox 1382 | \vskip -\dimen@ 1383 | \@textbottom 1384 | }% 1385 | \fi 1386 | \global \maxdepth \@maxdepth 1387 | } 1388 | \def\titlenote{\@ifnextchar[\@xtitlenote{\stepcounter\@mpfn 1389 | \global\advance\titlenotecount by 1 1390 | \ifnum\titlenotecount=1 1391 | \raisebox{9pt}{$\ast$} 1392 | \fi 1393 | \ifnum\titlenotecount=2 1394 | \raisebox{9pt}{$\dagger$} 1395 | \fi 1396 | \ifnum\titlenotecount=3 1397 | \raisebox{9pt}{$\ddagger$} 1398 | \fi 1399 | \ifnum\titlenotecount=4 1400 | \raisebox{9pt}{$\S$} 1401 | \fi 1402 | \ifnum\titlenotecount=5 1403 | \raisebox{9pt}{$\P$} 1404 | \fi 1405 | \@titlenotetext 1406 | }} 1407 | 1408 | \long\def\@titlenotetext#1{\insert\footins{% 1409 | \ifnum\titlenotecount=1\global\tntoks={#1}\fi 1410 | \ifnum\titlenotecount=2\global\tntokstwo={#1}\fi 1411 | \ifnum\titlenotecount=3\global\tntoksthree={#1}\fi 1412 | \ifnum\titlenotecount=4\global\tntoksfour={#1}\fi 1413 | \ifnum\titlenotecount=5\global\tntoksfive={#1}\fi 1414 | \reset@font\footnotesize 1415 | \interlinepenalty\interfootnotelinepenalty 1416 | \splittopskip\footnotesep 1417 | \splitmaxdepth \dp\strutbox \floatingpenalty \@MM 1418 | \hsize\columnwidth \@parboxrestore 1419 | \protected@edef\@currentlabel{% 1420 | }% 1421 | \color@begingroup 1422 | \color@endgroup}} 1423 | 1424 | %%%%%%%%%%%%%%%%%%%%%%%%% 1425 | \ps@plain 1426 | \baselineskip=11pt 1427 | \let\thepage\relax % For NO page numbers - GM Nov. 30th. 1999 and July 2000 1428 | \def\setpagenumber#1{\global\setcounter{page}{#1}} 1429 | %\pagenumbering{arabic} % Arabic page numbers GM July 2000 1430 | \twocolumn % Double column. 1431 | \flushbottom % Even bottom -- alas, does not balance columns at end of document 1432 | \pagestyle{plain} 1433 | 1434 | % Need Copyright Year and Copyright Data to be user definable (in .tex file). 1435 | % Gerry Nov. 30th. 1999 1436 | \newtoks\copyrtyr 1437 | \newtoks\acmcopyr 1438 | \newtoks\boilerplate 1439 | \global\acmcopyr={X-XXXXX-XX-X/XX/XX} % Default - 5/11/2001 *** Gerry 1440 | \global\copyrtyr={20XX} % Default - 3/3/2003 *** Gerry 1441 | \def\CopyrightYear#1{\global\copyrtyr{#1}} 1442 | \def\crdata#1{\global\acmcopyr{#1}} 1443 | \def\permission#1{\global\boilerplate{#1}} 1444 | % 1445 | \global\boilerplate={} 1446 | \newtoks\copyrightetc 1447 | \global\copyrightetc{} % Gerry changed to 15 May 2012 1448 | %\toappear{\the\boilerplate\par 1449 | %{\confname{\the\conf}} \the\confinfo\par \the\copyrightetc.} 1450 | %\DeclareFixedFont{\altcrnotice}{OT1}{tmr}{m}{n}{8} % << patch needed for accenting e.g. Montreal - Gerry, May 2007 1451 | %\DeclareFixedFont{\altconfname}{OT1}{tmr}{m}{it}{8} % << patch needed for accenting in italicized confname - Gerry, May 2007 1452 | % 1453 | %{\altconfname{{\the\conf}}} {\altcrnotice\the\confinfo\par} \the\copyrightetc.} % << Gerry, May 2007 1454 | % 1455 | % The following section (i.e. 3 .sty inclusions) was added in May 2007 so as to fix the problems that many 1456 | % authors were having with accents. Sometimes accents would occur, but the letter-character would be of a different 1457 | % font. Conversely the letter-character font would be correct but, e.g. a 'bar' would appear superimposed on the 1458 | % character instead of, say, an unlaut/diaresis. Sometimes the letter-character would NOT appear at all. 1459 | % Using [T1]{fontenc} outright was not an option as this caused 99% of the authors to 'produce' a Type-3 (bitmapped) 1460 | % PDF file - useless for production. 1461 | % 1462 | % For proper (font) accenting we NEED these packages to be part of the .cls file i.e. 'ae', 'aecompl' and 'aeguil' 1463 | % ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1464 | %% This is file `ae.sty' 1465 | \def\fileversion{1.3} 1466 | \def\filedate{2001/02/12} 1467 | \NeedsTeXFormat{LaTeX2e} 1468 | %\ProvidesPackage{ae}[\filedate\space\fileversion\space % GM 1469 | % Almost European Computer Modern] % GM - keeping the log file clean(er) 1470 | \newif\if@ae@slides \@ae@slidesfalse 1471 | \DeclareOption{slides}{\@ae@slidestrue} 1472 | \ProcessOptions 1473 | \fontfamily{aer} 1474 | \RequirePackage[T1]{fontenc} 1475 | \if@ae@slides 1476 | \renewcommand{\sfdefault}{laess} 1477 | \renewcommand{\rmdefault}{laess} % no roman 1478 | \renewcommand{\ttdefault}{laett} 1479 | \else 1480 | \renewcommand{\sfdefault}{aess} 1481 | \renewcommand{\rmdefault}{aer} 1482 | \renewcommand{\ttdefault}{aett} 1483 | \fi 1484 | \endinput 1485 | %% 1486 | %% End of file `ae.sty'. 1487 | % 1488 | % 1489 | \def\fileversion{0.9} 1490 | \def\filedate{1998/07/23} 1491 | \NeedsTeXFormat{LaTeX2e} 1492 | %\ProvidesPackage{aecompl}[\filedate\space\fileversion\space % GM 1493 | %T1 Complements for AE fonts (D. Roegel)] % GM -- keeping the log file clean(er) 1494 | 1495 | \def\@ae@compl#1{{\fontencoding{T1}\fontfamily{cmr}\selectfont\symbol{#1}}} 1496 | \def\guillemotleft{\@ae@compl{19}} 1497 | \def\guillemotright{\@ae@compl{20}} 1498 | \def\guilsinglleft{\@ae@compl{14}} 1499 | \def\guilsinglright{\@ae@compl{15}} 1500 | \def\TH{\@ae@compl{222}} 1501 | \def\NG{\@ae@compl{141}} 1502 | \def\ng{\@ae@compl{173}} 1503 | \def\th{\@ae@compl{254}} 1504 | \def\DJ{\@ae@compl{208}} 1505 | \def\dj{\@ae@compl{158}} 1506 | \def\DH{\@ae@compl{208}} 1507 | \def\dh{\@ae@compl{240}} 1508 | \def\@perthousandzero{\@ae@compl{24}} 1509 | \def\textperthousand{\%\@perthousandzero} 1510 | \def\textpertenthousand{\%\@perthousandzero\@perthousandzero} 1511 | \endinput 1512 | % 1513 | % 1514 | %% This is file `aeguill.sty' 1515 | % This file gives french guillemets (and not guillemots!) 1516 | % built with the Polish CMR fonts (default), WNCYR fonts, the LASY fonts 1517 | % or with the EC fonts. 1518 | % This is useful in conjunction with the ae package 1519 | % (this package loads the ae package in case it has not been loaded) 1520 | % and with or without the french(le) package. 1521 | % 1522 | % In order to get the guillemets, it is necessary to either type 1523 | % \guillemotleft and \guillemotright, or to use an 8 bit encoding 1524 | % (such as ISO-Latin1) which selects these two commands, 1525 | % or, if you use the french package (but not the frenchle package), 1526 | % to type << or >>. 1527 | % 1528 | % By default, you get the Polish CMR guillemets; if this package is loaded 1529 | % with the `cm' option, you get the LASY guillemets; with `ec,' you 1530 | % get the EC guillemets, and with `cyr,' you get the cyrillic guillemets. 1531 | % 1532 | % In verbatim mode, you always get the EC/TT guillemets. 1533 | % 1534 | % The default option is interesting in conjunction with PDF, 1535 | % because there is a Type 1 version of the Polish CMR fonts 1536 | % and these guillemets are very close in shape to the EC guillemets. 1537 | % There are no free Type 1 versions of the EC fonts. 1538 | % 1539 | % Support for Polish CMR guillemets was kindly provided by 1540 | % Rolf Niepraschk in version 0.99 (2000/05/22). 1541 | % Bernd Raichle provided extensive simplifications to the code 1542 | % for version 1.00. 1543 | % 1544 | % This package is released under the LPPL. 1545 | % 1546 | % Changes: 1547 | % Date version 1548 | % 2001/04/12 1.01 the frenchle and french package are now distinguished. 1549 | % 1550 | \def\fileversion{1.01} 1551 | \def\filedate{2001/04/12} 1552 | \NeedsTeXFormat{LaTeX2e} 1553 | %\ProvidesPackage{aeguill}[2001/04/12 1.01 % % GM 1554 | %AE fonts with french guillemets (D. Roegel)] % GM - keeping the log file clean(er) 1555 | %\RequirePackage{ae} % GM May 2007 - already embedded here 1556 | 1557 | \newcommand{\@ae@switch}[4]{#4} 1558 | \DeclareOption{ec}{\renewcommand\@ae@switch[4]{#1}} 1559 | \DeclareOption{cm}{\renewcommand\@ae@switch[4]{#2}} 1560 | \DeclareOption{cyr}{\renewcommand\@ae@switch[4]{#3}} 1561 | \DeclareOption{pl}{\renewcommand\@ae@switch[4]{#4}} 1562 | \ExecuteOptions{pl} 1563 | \ProcessOptions 1564 | 1565 | % 1566 | % Load necessary packages 1567 | % 1568 | \@ae@switch{% ec 1569 | % do nothing 1570 | }{% cm 1571 | \RequirePackage{latexsym}% GM - May 2007 - already 'mentioned as required' up above 1572 | }{% cyr 1573 | \RequirePackage[OT2,T1]{fontenc}% 1574 | }{% pl 1575 | \RequirePackage[OT4,T1]{fontenc}% 1576 | } 1577 | 1578 | % The following command will be compared to \frenchname, 1579 | % as defined in french.sty and frenchle.sty. 1580 | \def\aeguillfrenchdefault{french}% 1581 | 1582 | \let\guill@verbatim@font\verbatim@font 1583 | \def\verbatim@font{\guill@verbatim@font\ecguills{cmtt}% 1584 | \let\guillemotleft\@oguills\let\guillemotright\@fguills} 1585 | 1586 | \begingroup \catcode`\<=13 \catcode`\>=13 1587 | \def\x{\endgroup 1588 | \def\ae@lfguill{<<}% 1589 | \def\ae@rfguill{>>}% 1590 | }\x 1591 | 1592 | \newcommand{\ecguills}[1]{% 1593 | \def\selectguillfont{\fontencoding{T1}\fontfamily{#1}\selectfont}% 1594 | \def\@oguills{{\selectguillfont\symbol{19}}}% 1595 | \def\@fguills{{\selectguillfont\symbol{20}}}% 1596 | } 1597 | 1598 | \newcommand{\aeguills}{% 1599 | \ae@guills 1600 | % We redefine \guillemotleft and \guillemotright 1601 | % in order to catch them when they are used 1602 | % with \DeclareInputText (in latin1.def for instance) 1603 | % We use \auxWARNINGi as a safe indicator that french.sty is used. 1604 | \gdef\guillemotleft{\ifx\auxWARNINGi\undefined 1605 | \@oguills % neither french.sty nor frenchle.sty 1606 | \else 1607 | \ifx\aeguillfrenchdefault\frenchname 1608 | \ae@lfguill % french.sty 1609 | \else 1610 | \@oguills % frenchle.sty 1611 | \fi 1612 | \fi}% 1613 | \gdef\guillemotright{\ifx\auxWARNINGi\undefined 1614 | \@fguills % neither french.sty nor frenchle.sty 1615 | \else 1616 | \ifx\aeguillfrenchdefault\frenchname 1617 | \ae@rfguill % french.sty 1618 | \else 1619 | \@fguills % frenchle.sty 1620 | \fi 1621 | \fi}% 1622 | } 1623 | 1624 | % 1625 | % Depending on the class option 1626 | % define the internal command \ae@guills 1627 | \@ae@switch{% ec 1628 | \newcommand{\ae@guills}{% 1629 | \ecguills{cmr}}% 1630 | }{% cm 1631 | \newcommand{\ae@guills}{% 1632 | \def\selectguillfont{\fontencoding{U}\fontfamily{lasy}% 1633 | \fontseries{m}\fontshape{n}\selectfont}% 1634 | \def\@oguills{\leavevmode\nobreak 1635 | \hbox{\selectguillfont (\kern-.20em(\kern.20em}\nobreak}% 1636 | \def\@fguills{\leavevmode\nobreak 1637 | \hbox{\selectguillfont \kern.20em)\kern-.2em)}% 1638 | \ifdim\fontdimen\@ne\font>\z@\/\fi}}% 1639 | }{% cyr 1640 | \newcommand{\ae@guills}{% 1641 | \def\selectguillfont{\fontencoding{OT2}\fontfamily{wncyr}\selectfont}% 1642 | \def\@oguills{{\selectguillfont\symbol{60}}}% 1643 | \def\@fguills{{\selectguillfont\symbol{62}}}} 1644 | }{% pl 1645 | \newcommand{\ae@guills}{% 1646 | \def\selectguillfont{\fontencoding{OT4}\fontfamily{cmr}\selectfont}% 1647 | \def\@oguills{{\selectguillfont\symbol{174}}}% 1648 | \def\@fguills{{\selectguillfont\symbol{175}}}} 1649 | } 1650 | 1651 | 1652 | \AtBeginDocument{% 1653 | \ifx\GOfrench\undefined 1654 | \aeguills 1655 | \else 1656 | \let\aeguill@GOfrench\GOfrench 1657 | \gdef\GOfrench{\aeguill@GOfrench \aeguills}% 1658 | \fi 1659 | } 1660 | 1661 | \endinput 1662 | % 1663 | 1664 | -------------------------------------------------------------------------------- /include/AuxGraph.h: -------------------------------------------------------------------------------- 1 | #ifndef AUXGRAPH_H 2 | #define AUXGRAPH_H 3 | 4 | #include "llvm/ADT/DenseMap.h" 5 | #include "llvm/ADT/DenseSet.h" 6 | #include "llvm/ADT/MapVector.h" 7 | #include "llvm/ADT/SetVector.h" 8 | #include "llvm/IR/BasicBlock.h" 9 | #include "llvm/IR/Function.h" 10 | 11 | #include 12 | 13 | using namespace llvm; 14 | 15 | namespace epp { 16 | 17 | struct Edge { 18 | BasicBlock *src, *tgt; 19 | bool real; 20 | Edge(BasicBlock *from, BasicBlock *to, bool r = true) 21 | : src(from), tgt(to), real(r) {} 22 | }; 23 | 24 | typedef std::shared_ptr EdgePtr; 25 | 26 | // An auxiliary graph representation of the CFG of a function which 27 | // will be queried online during instrumentation. Edges in the graph 28 | // will need to be updated as instrumentation changes the basic block 29 | // pointers used to represent a particular edge/node. 30 | class AuxGraph { 31 | 32 | SmallVector Nodes; 33 | DenseMap> EdgeList; 34 | std::unordered_map> SegmentMap; 35 | std::unordered_map Weights; 36 | BasicBlock *FakeExit; 37 | 38 | public: 39 | void clear(); 40 | void init(Function &F); 41 | EdgePtr add(BasicBlock *src, BasicBlock *tgt, bool isReal = true); 42 | void 43 | segment(SetVector> &List); 44 | //void printWeights(); 45 | void dot(raw_ostream &os) const; 46 | void dotW(raw_ostream &os) const; 47 | SmallVector succs(BasicBlock *B) const; 48 | SmallVector, 16> getWeights() const; 49 | APInt getEdgeWeight(const EdgePtr &Ptr) const; 50 | std::unordered_map> getSegmentMap() const; 51 | EdgePtr exists(BasicBlock *Src, BasicBlock *Tgt, bool isReal) const; 52 | EdgePtr getOrInsertEdge(BasicBlock *Src, BasicBlock *Tgt, bool isReal); 53 | 54 | bool isExitBlock(BasicBlock *B) const { return B == FakeExit; } 55 | SmallVector nodes() const { return Nodes; } 56 | APInt &operator[](const EdgePtr &E) { return Weights[E]; } 57 | }; 58 | } 59 | #endif 60 | -------------------------------------------------------------------------------- /include/BreakSelfLoopsPass.h: -------------------------------------------------------------------------------- 1 | #ifndef BREAKSELFLOOPSPASS_H 2 | #define BREAKSELFLOOPSPASS_H 3 | 4 | #include "llvm/Pass.h" 5 | 6 | using namespace llvm; 7 | 8 | namespace epp { 9 | 10 | struct BreakSelfLoopsPass : public ModulePass { 11 | static char ID; 12 | BreakSelfLoopsPass() : llvm::ModulePass(ID){} 13 | virtual bool runOnModule(llvm::Module &m) override; 14 | llvm::StringRef getPassName() const override { return "BreakSelfLoopsPass"; } 15 | }; 16 | 17 | } 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /include/EPPDecode.h: -------------------------------------------------------------------------------- 1 | #ifndef EPPDECODE_H 2 | #define EPPDECODE_H 3 | 4 | #include "llvm/ADT/APInt.h" 5 | #include "llvm/ADT/StringRef.h" 6 | #include "llvm/Analysis/LoopInfo.h" 7 | #include "llvm/IR/Module.h" 8 | #include "llvm/Pass.h" 9 | 10 | #include "EPPEncode.h" 11 | #include 12 | #include 13 | 14 | namespace epp { 15 | 16 | enum PathType { RIRO, FIRO, RIFO, FIFO }; 17 | 18 | struct Path { 19 | APInt Id; 20 | uint64_t Freq; 21 | PathType Type; 22 | std::vector Blocks; 23 | }; 24 | 25 | struct EPPDecode : public llvm::ModulePass { 26 | static char ID; 27 | //std::string filename; 28 | 29 | DenseMap FunctionIdToPtr; 30 | llvm::DenseMap> DecodeCache; 31 | 32 | EPPDecode() : llvm::ModulePass(ID) {} 33 | 34 | virtual void getAnalysisUsage(llvm::AnalysisUsage &au) const override { 35 | au.addRequired(); 36 | } 37 | 38 | virtual bool runOnModule(llvm::Module &m) override; 39 | bool doInitialization(llvm::Module &m) override; 40 | 41 | void getPathInfo(uint32_t FunctionId, Path& Info); 42 | 43 | std::pair> 44 | decode(llvm::Function &F, llvm::APInt pathID, EPPEncode &E); 45 | 46 | llvm::StringRef getPassName() const override { return "EPPDecode"; } 47 | }; 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /include/EPPEncode.h: -------------------------------------------------------------------------------- 1 | #ifndef EPPENCODE_H 2 | #define EPPENCODE_H 3 | 4 | #include "llvm/ADT/APInt.h" 5 | #include "llvm/ADT/DenseMap.h" 6 | #include "llvm/ADT/MapVector.h" 7 | #include "llvm/ADT/SetVector.h" 8 | #include "llvm/Analysis/LoopInfo.h" 9 | #include "llvm/IR/BasicBlock.h" 10 | #include "llvm/IR/Module.h" 11 | #include "llvm/Pass.h" 12 | #include "llvm/Support/CommandLine.h" 13 | #include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h" 14 | 15 | #include 16 | #include 17 | 18 | //#include "AltCFG.h" 19 | #include "AuxGraph.h" 20 | 21 | namespace epp { 22 | 23 | struct EPPEncode : public llvm::FunctionPass { 24 | 25 | static char ID; 26 | 27 | llvm::LoopInfo *LI; 28 | llvm::DenseMap numPaths; 29 | // altcfg ACFG; 30 | AuxGraph AG; 31 | 32 | EPPEncode() : llvm::FunctionPass(ID), LI(nullptr) {} 33 | 34 | virtual void getAnalysisUsage(llvm::AnalysisUsage &au) const override { 35 | au.addRequired(); 36 | au.setPreservesAll(); 37 | } 38 | 39 | virtual bool runOnFunction(llvm::Function &f) override; 40 | void encode(llvm::Function &f); 41 | bool doInitialization(llvm::Module &m) override; 42 | bool doFinalization(llvm::Module &m) override; 43 | void releaseMemory() override; 44 | llvm::StringRef getPassName() const override { return "EPPEncode"; } 45 | }; 46 | } 47 | #endif 48 | -------------------------------------------------------------------------------- /include/EPPPathPrinter.h: -------------------------------------------------------------------------------- 1 | #ifndef EPPPATHPRINTER_H 2 | #define EPPPATHPRINTER_H 3 | 4 | #include "llvm/ADT/APInt.h" 5 | #include "llvm/ADT/StringRef.h" 6 | #include "llvm/Analysis/LoopInfo.h" 7 | #include "llvm/IR/Module.h" 8 | #include "llvm/Pass.h" 9 | 10 | #include "EPPDecode.h" 11 | #include 12 | #include 13 | 14 | namespace epp { 15 | 16 | struct EPPPathPrinter : public llvm::ModulePass { 17 | static char ID; 18 | DenseMap FunctionIdToPtr; 19 | EPPPathPrinter() : llvm::ModulePass(ID) {} 20 | 21 | virtual void getAnalysisUsage(llvm::AnalysisUsage &au) const override { 22 | au.addRequired(); 23 | au.addRequired(); 24 | } 25 | 26 | virtual bool runOnModule(llvm::Module &m) override; 27 | bool doInitialization(llvm::Module &m) override; 28 | llvm::StringRef getPassName() const override { return "EPPPathPrinter"; } 29 | }; 30 | } 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /include/EPPProfile.h: -------------------------------------------------------------------------------- 1 | #ifndef EPPPROFILE_H 2 | #define EPPPROFILE_H 3 | #include "llvm/ADT/DenseMap.h" 4 | #include "llvm/Analysis/LoopInfo.h" 5 | #include "llvm/IR/Module.h" 6 | #include "llvm/Pass.h" 7 | 8 | #include "EPPEncode.h" 9 | 10 | namespace epp { 11 | struct EPPProfile : public llvm::ModulePass { 12 | static char ID; 13 | 14 | llvm::LoopInfo *LI; 15 | llvm::DenseMap FunctionIds; 16 | 17 | EPPProfile() : llvm::ModulePass(ID), LI(nullptr) {} 18 | 19 | virtual void getAnalysisUsage(llvm::AnalysisUsage &au) const override { 20 | // au.addRequired(); 21 | au.addRequired(); 22 | } 23 | 24 | virtual bool runOnModule(llvm::Module &m) override; 25 | void instrument(llvm::Function &F, EPPEncode &E); 26 | void addCtorsAndDtors(llvm::Module &Mod); 27 | 28 | bool doInitialization(llvm::Module &m) override; 29 | bool doFinalization(llvm::Module &m) override; 30 | llvm::StringRef getPassName() const override { return "EPPProfile"; } 31 | }; 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /include/SplitLandingPadPredsPass.h: -------------------------------------------------------------------------------- 1 | #ifndef SPLITLANDINGPADPREDSPASS_H 2 | #define SPLITLANDINGPADPREDSPASS_H 3 | 4 | #include "llvm/Pass.h" 5 | 6 | using namespace llvm; 7 | 8 | namespace epp { 9 | 10 | struct SplitLandingPadPredsPass : public ModulePass { 11 | static char ID; 12 | SplitLandingPadPredsPass() : llvm::ModulePass(ID){} 13 | virtual bool runOnModule(llvm::Module &m) override; 14 | llvm::StringRef getPassName() const override { return "SplitLandingPadPredsPass"; } 15 | }; 16 | 17 | } 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(epp) 2 | -------------------------------------------------------------------------------- /lib/epp/AuxGraph.cpp: -------------------------------------------------------------------------------- 1 | #define DEBUG_TYPE "epp_auxg" 2 | #include "AuxGraph.h" 3 | #include "llvm/ADT/DenseSet.h" 4 | #include "llvm/ADT/SCCIterator.h" 5 | #include "llvm/ADT/SetVector.h" 6 | #include "llvm/Analysis/CFG.h" 7 | #include "llvm/Support/Debug.h" 8 | #include "llvm/Support/raw_ostream.h" 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | using namespace epp; 14 | 15 | namespace { 16 | 17 | void postorderHelper(BasicBlock *toVisit, vector &blocks, 18 | DenseSet &seen, 19 | const set &SCCBlocks) { 20 | seen.insert(toVisit); 21 | for (auto s = succ_begin(toVisit), e = succ_end(toVisit); s != e; ++s) { 22 | 23 | // Don't need to worry about backedge successors as their targets 24 | // will be visited already and will fail the first condition check. 25 | 26 | if (!seen.count(*s) && (SCCBlocks.find(*s) != SCCBlocks.end())) { 27 | postorderHelper(*s, blocks, seen, SCCBlocks); 28 | } 29 | } 30 | blocks.push_back(toVisit); 31 | } 32 | 33 | vector postOrder(BasicBlock *Block, 34 | const set &SCCBlocks) { 35 | vector ordered; 36 | DenseSet seen; 37 | postorderHelper(Block, ordered, seen, SCCBlocks); 38 | return ordered; 39 | } 40 | 41 | SmallVector postOrder(Function &F) { 42 | SmallVector PostOrderBlocks; 43 | 44 | // Add all the basicblocks in the function to a set. 45 | SetVector BasicBlocks; 46 | for (auto &BB : F) 47 | BasicBlocks.insert(&BB); 48 | 49 | for (auto I = scc_begin(&F), IE = scc_end(&F); I != IE; ++I) { 50 | 51 | // Obtain the vector of BBs 52 | const std::vector &SCCBBs = *I; 53 | 54 | // Find an entry block into the current SCC as the starting point 55 | // of the DFS for the postOrder traversal. Now the *entry* block 56 | // should have predecessors in other SCC's which are topologically 57 | // before this SCC, i.e blocks not seen yet. 58 | 59 | // Remove each basic block which we encounter in the current SCC. 60 | // Remaining blocks must be topologically earlier than the blocks 61 | // we have seen already. 62 | DEBUG(errs() << "SCC: "); 63 | for (auto *BB : SCCBBs) { 64 | DEBUG(errs() << BB->getName() << " "); 65 | BasicBlocks.remove(BB); 66 | } 67 | DEBUG(errs() << "\n"); 68 | 69 | // Find the first block in the current SCC to have a predecessor 70 | // in the remaining blocks. This becomes the starting block for the DFS 71 | // Exception: SCC size = 1. We rely on the fact that the ordering of 72 | // predecessors is deterministic. 73 | 74 | BasicBlock *Start = nullptr; 75 | 76 | for (int i = 0; i < SCCBBs.size() && Start == nullptr; i++) { 77 | auto BB = SCCBBs[i]; 78 | for (auto P = pred_begin(BB), E = pred_end(BB); P != E; P++) { 79 | if (BasicBlocks.count(*P)) { 80 | Start = BB; 81 | break; 82 | } 83 | } 84 | } 85 | 86 | if (!Start) { 87 | Start = SCCBBs[0]; 88 | assert(SCCBBs.size() == 1 && 89 | "Should be entry block only which has no preds"); 90 | } 91 | 92 | set SCCBlocksSet(SCCBBs.begin(), SCCBBs.end()); 93 | auto blocks = postOrder(Start, SCCBlocksSet); 94 | 95 | assert(SCCBBs.size() == blocks.size() && 96 | "Could not discover all blocks"); 97 | 98 | for (auto *BB : blocks) { 99 | PostOrderBlocks.push_back(BB); 100 | } 101 | } 102 | 103 | DEBUG(errs() << "Post Order Blocks: \n"); 104 | for (auto &POB : PostOrderBlocks) 105 | DEBUG(errs() << POB->getName() << " "); 106 | DEBUG(errs() << "\n"); 107 | 108 | return PostOrderBlocks; 109 | } 110 | } 111 | 112 | // void AuxGraph::printWeights() { 113 | // for (auto &V : Weights) { 114 | // errs() << V.first->src->getName() << "-" << V.first->tgt->getName() 115 | // << ": " << V.second << "\n"; 116 | // } 117 | // } 118 | 119 | /// Construct the auxiliary graph representation from the original 120 | /// function control flow graph. At this stage the CFG and the 121 | /// AuxGraph are the same graph. 122 | void AuxGraph::init(Function &F) { 123 | Nodes = postOrder(F); 124 | SmallVector Leaves; 125 | for (auto &BB : Nodes) { 126 | if (BB->getTerminator()->getNumSuccessors() > 0) { 127 | for (auto S = succ_begin(BB), E = succ_end(BB); S != E; S++) { 128 | add(BB, *S); 129 | } 130 | } else { 131 | Leaves.push_back(BB); 132 | } 133 | } 134 | 135 | // Create a dummy basic block to represent the fake exit 136 | FakeExit = BasicBlock::Create(F.getContext(), "fake.exit"); 137 | 138 | // For each leaf (block with no successor in the original CFG), add 139 | // an edge from it to the fake exit. So the only block with no successor 140 | // is the fake exit block wrt to the AuxGraph. 141 | for (auto &L : Leaves) { 142 | add(L, FakeExit, false); 143 | } 144 | 145 | Nodes.insert(Nodes.begin(), FakeExit); 146 | 147 | /// Special case when there is only 1 basic block in the function 148 | /// if (Nodes.size() == 1) { 149 | /// auto *src = Nodes.front(); 150 | /// EdgeList.insert({src, SmallVector()}); 151 | /// } 152 | } 153 | 154 | /// Add a new edge to the edge list. This method is only used for 155 | /// adding real edges by the constructor. 156 | EdgePtr AuxGraph::add(BasicBlock *src, BasicBlock *tgt, bool isReal) { 157 | if (EdgeList.count(src) == 0) { 158 | EdgeList.insert({src, SmallVector()}); 159 | } 160 | auto E = make_shared(src, tgt, isReal); 161 | EdgeList[src].push_back(E); 162 | return E; 163 | } 164 | 165 | EdgePtr AuxGraph::exists(BasicBlock *Src, BasicBlock *Tgt, bool isReal) const { 166 | for (auto &SE : succs(Src)) { 167 | if (SE->tgt == Tgt && SE->real == isReal) { 168 | return SE; 169 | } 170 | } 171 | return nullptr; 172 | } 173 | 174 | EdgePtr AuxGraph::getOrInsertEdge(BasicBlock *Src, BasicBlock *Tgt, 175 | bool isReal) { 176 | if (auto E = exists(Src, Tgt, isReal)) { 177 | return E; 178 | } 179 | return add(Src, Tgt, isReal); 180 | } 181 | 182 | /// List of edges to be *segmented*. A segmented edge is an edge which 183 | /// exists in the original CFG but is replaced by two edges in the 184 | /// AuxGraph. An edge from A->B, is replaced by {A->Exit, Entry->B}. 185 | /// An edge can only be segmented once. This 186 | void AuxGraph::segment( 187 | SetVector> &List) { 188 | SmallVector SegmentList; 189 | /// Move the internal EdgePtr from the EdgeList to the SegmentList 190 | for (auto &L : List) { 191 | auto *Src = L.first, *Tgt = L.second; 192 | 193 | assert(EdgeList.count(Src) && 194 | "Source basicblock not found in edge list."); 195 | auto &Edges = EdgeList[Src]; 196 | auto it = find_if(Edges.begin(), Edges.end(), 197 | [&Tgt](EdgePtr &P) { return P->tgt == Tgt; }); 198 | assert(it != Edges.end() && 199 | "Target basicblock not found in edge list."); 200 | assert(SegmentMap.count(*it) == 0 && 201 | "An edge can only be segmented once."); 202 | SegmentList.push_back(move(*it)); 203 | Edges.erase(it); 204 | } 205 | 206 | /// Add two new edges for each edge in the SegmentList. Update the EdgeList. 207 | /// An edge from A->B, is replaced by {A->Exit, Entry->B}. 208 | auto &Entry = Nodes.back(), &Exit = Nodes.front(); 209 | for (auto &S : SegmentList) { 210 | auto *A = S->src, *B = S->tgt; 211 | // errs() << "Segmenting: " << A->getName() << "-" << B->getName() << 212 | // "\n"; 213 | auto AExit = make_shared(A, Exit, false); 214 | auto EntryB = make_shared(Entry, B, false); 215 | // errs() << "Output: " << A->getName() << "-" << Exit->getName() 216 | //<< "," << Entry->getName() << "-" << B->getName() << "\n"; 217 | EdgeList[A].push_back(AExit); 218 | EdgeList[Entry].push_back(EntryB); 219 | SegmentMap.insert({S, {AExit, EntryB}}); 220 | } 221 | } 222 | 223 | /// Get all non-zero weights for non-segmented edges. 224 | SmallVector, 16> AuxGraph::getWeights() const { 225 | SmallVector, 16> Result; 226 | copy_if(Weights.begin(), Weights.end(), back_inserter(Result), 227 | [](const pair &V) { 228 | return V.first->real && V.second.ne(APInt(64, 0, true)); 229 | }); 230 | return Result; 231 | } 232 | 233 | /// Get the segment mapping 234 | std::unordered_map> 235 | AuxGraph::getSegmentMap() const { 236 | return SegmentMap; 237 | } 238 | 239 | /// Get weight for a specific edge. 240 | APInt AuxGraph::getEdgeWeight(const EdgePtr &Ptr) const { 241 | return Weights.at(Ptr); 242 | } 243 | 244 | /// Return the successors edges of a basicblock from the Auxiliary Graph. 245 | SmallVector AuxGraph::succs(BasicBlock *B) const { 246 | return EdgeList.lookup(B); 247 | } 248 | 249 | /// Print out the AuxGraph in Graphviz format. Defaults to printing to 250 | /// llvm::errs() 251 | void AuxGraph::dot(raw_ostream &os = errs()) const { 252 | os << "digraph \"AuxGraph\" {\n label=\"AuxGraph\";\n"; 253 | for (auto &N : Nodes) { 254 | os << "\tNode" << N << " [shape=record, label=\"" << N->getName().str() 255 | << "\"];\n"; 256 | } 257 | for (auto &EL : EdgeList) { 258 | for (auto &L : EL.getSecond()) { 259 | os << "\tNode" << EL.getFirst() << " -> Node" << L->tgt 260 | << " [style=solid,"; 261 | if (!L->real) 262 | os << "color=\"red\","; 263 | // os << " label=\"" << Weights[L] << "\"];\n"; 264 | os << " label=\"" 265 | << "\"];\n"; 266 | } 267 | } 268 | os << "}\n"; 269 | } 270 | 271 | /// Print out the AuxGraph in Graphviz format. Defaults to printing to 272 | /// llvm::errs() 273 | void AuxGraph::dotW(raw_ostream &os = errs()) const { 274 | os << "digraph \"AuxGraph\" {\n label=\"AuxGraph\";\n"; 275 | for (auto &N : Nodes) { 276 | os << "\tNode" << N << " [shape=record, label=\"" << N->getName().str() 277 | << "\"];\n"; 278 | } 279 | for (auto &EL : EdgeList) { 280 | for (auto &L : EL.getSecond()) { 281 | os << "\tNode" << EL.getFirst() << " -> Node" << L->tgt 282 | << " [style=solid,"; 283 | if (!L->real) 284 | os << "color=\"red\","; 285 | os << " label=\"" << Weights.at(L) << "\"];\n"; 286 | } 287 | } 288 | os << "}\n"; 289 | } 290 | 291 | /// Clear all internal state; to be called by the releaseMemory function 292 | void AuxGraph::clear() { 293 | Nodes.clear(), EdgeList.clear(), SegmentMap.clear(), Weights.clear(); 294 | } 295 | -------------------------------------------------------------------------------- /lib/epp/BreakSelfLoopsPass.cpp: -------------------------------------------------------------------------------- 1 | #include "BreakSelfLoopsPass.h" 2 | #include "llvm/Analysis/CFG.h" 3 | #include "llvm/IR/Instructions.h" 4 | #include "llvm/IR/Module.h" 5 | #include "llvm/Support/raw_ostream.h" 6 | #include "llvm/Transforms/IPO.h" 7 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 8 | 9 | using namespace epp; 10 | 11 | namespace { 12 | 13 | bool BreakSelfLoops(Function &F) { 14 | bool Changed = false; 15 | 16 | SmallVector SelfLoops; 17 | for (auto &BB : F) { 18 | for (auto S = succ_begin(&BB), E = succ_end(&BB); S != E; S++) { 19 | if (*S == &BB) 20 | SelfLoops.push_back(&BB); 21 | } 22 | } 23 | 24 | for (auto BB : SelfLoops) { 25 | Changed |= (bool)SplitEdge(BB, BB); 26 | } 27 | 28 | return Changed; 29 | } 30 | } 31 | 32 | /// While BreakCriticalEdges should break most self loops, sometimes it 33 | /// does not if the self loop does not have a successor apart from itself, 34 | /// ie. it is an infinite loop. We find this to occur in 401.bzip2, 35 | /// handle_compress. 36 | bool BreakSelfLoopsPass::runOnModule(Module &M) { 37 | bool Changed = false; 38 | for (auto &F : M) { 39 | if (F.isDeclaration()) 40 | continue; 41 | Changed |= BreakSelfLoops(F); 42 | } 43 | 44 | return Changed; 45 | } 46 | 47 | char BreakSelfLoopsPass::ID = 0; 48 | -------------------------------------------------------------------------------- /lib/epp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_library(epp-inst 3 | EPPProfile.cpp 4 | EPPEncode.cpp 5 | EPPDecode.cpp 6 | AuxGraph.cpp 7 | EPPPathPrinter.cpp 8 | SplitLandingPadPredsPass.cpp 9 | BreakSelfLoopsPass.cpp 10 | ) 11 | 12 | 13 | add_library(epp-rt SHARED 14 | Runtime.cpp 15 | ) 16 | 17 | 18 | install(TARGETS epp-rt 19 | LIBRARY DESTINATION lib) 20 | -------------------------------------------------------------------------------- /lib/epp/EPPDecode.cpp: -------------------------------------------------------------------------------- 1 | #define DEBUG_TYPE "epp_decode" 2 | #include "llvm/ADT/SmallString.h" 3 | #include "llvm/Analysis/LoopInfo.h" 4 | #include "llvm/IR/BasicBlock.h" 5 | #include "llvm/IR/CallSite.h" 6 | #include "llvm/IR/Constants.h" 7 | #include "llvm/IR/DebugInfo.h" 8 | #include "llvm/IR/Instructions.h" 9 | #include "llvm/Support/Debug.h" 10 | #include "llvm/Support/raw_ostream.h" 11 | 12 | #include "EPPDecode.h" 13 | 14 | #include 15 | #include 16 | 17 | using namespace llvm; 18 | using namespace epp; 19 | using namespace std; 20 | 21 | namespace { 22 | 23 | // inline bool isExitBlock(BasicBlock *BB) { 24 | // if (BB->getTerminator()->getNumSuccessors() == 0) 25 | // return true; 26 | // return false; 27 | // } 28 | } 29 | 30 | bool EPPDecode::doInitialization(Module &M) { 31 | uint32_t Id = 0; 32 | for (auto &F : M) { 33 | FunctionIdToPtr[Id++] = &F; 34 | } 35 | return false; 36 | } 37 | 38 | bool EPPDecode::runOnModule(Module &M) { return false; } 39 | 40 | void EPPDecode::getPathInfo(uint32_t FunctionId, Path &Info) { 41 | auto &F = *FunctionIdToPtr[FunctionId]; 42 | EPPEncode &Enc = getAnalysis(F); 43 | auto R = decode(F, Info.Id, Enc); 44 | Info.Type = R.first; 45 | Info.Blocks = R.second; 46 | } 47 | 48 | pair> 49 | EPPDecode::decode(Function &F, APInt pathID, EPPEncode &E) { 50 | vector Sequence; 51 | auto *Position = &F.getEntryBlock(); 52 | 53 | auto &AG = E.AG; 54 | 55 | DEBUG(errs() << "Decode Called On: " << pathID << "\n"); 56 | 57 | vector SelectedEdges; 58 | while (true) { 59 | Sequence.push_back(Position); 60 | if (AG.isExitBlock(Position)) 61 | break; 62 | APInt Wt(64, 0, true); 63 | EdgePtr Select = nullptr; 64 | DEBUG(errs() << Position->getName() << " (\n"); 65 | for (auto &Edge : AG.succs(Position)) { 66 | auto EWt = AG.getEdgeWeight(Edge); 67 | if (EWt.uge(Wt) && EWt.ule(pathID)) { 68 | DEBUG(errs() 69 | << "\t" << Edge->tgt->getName() << " [" << EWt << "]\n"); 70 | Select = Edge; 71 | Wt = EWt; 72 | } 73 | } 74 | DEBUG(errs() << " )\n\n\n"); 75 | 76 | SelectedEdges.push_back(Select); 77 | Position = Select->tgt; 78 | pathID -= Wt; 79 | } 80 | 81 | if (SelectedEdges.empty()) 82 | return {RIRO, Sequence}; 83 | 84 | #define SET_BIT(n, x) (n |= 1ULL << x) 85 | uint64_t Type = 0; 86 | if (!SelectedEdges.front()->real) { 87 | SET_BIT(Type, 0); 88 | } 89 | if (!SelectedEdges.back()->real) { 90 | SET_BIT(Type, 1); 91 | } 92 | #undef SET_BIT 93 | 94 | return {static_cast(Type), 95 | vector(Sequence.begin() + bool(Type & 0x1), 96 | Sequence.end() - bool(Type & 0x2))}; 97 | } 98 | 99 | char EPPDecode::ID = 0; 100 | -------------------------------------------------------------------------------- /lib/epp/EPPEncode.cpp: -------------------------------------------------------------------------------- 1 | #define DEBUG_TYPE "epp_encode" 2 | #include "llvm/ADT/MapVector.h" 3 | #include "llvm/ADT/PostOrderIterator.h" 4 | #include "llvm/ADT/SCCIterator.h" 5 | #include "llvm/ADT/SetVector.h" 6 | #include "llvm/ADT/Statistic.h" 7 | #include "llvm/Analysis/CFG.h" 8 | #include "llvm/Analysis/CFGPrinter.h" 9 | #include "llvm/IR/BasicBlock.h" 10 | #include "llvm/IR/CFG.h" 11 | #include "llvm/IR/Instructions.h" 12 | #include "llvm/IR/LegacyPassManager.h" 13 | #include "llvm/Pass.h" 14 | #include "llvm/Support/CommandLine.h" 15 | #include "llvm/Support/Debug.h" 16 | #include "llvm/Support/FileSystem.h" 17 | #include "llvm/Support/raw_ostream.h" 18 | #include "llvm/Transforms/Scalar.h" 19 | 20 | #include "AuxGraph.h" 21 | #include "EPPEncode.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | using namespace llvm; 30 | using namespace epp; 31 | using namespace std; 32 | 33 | extern cl::opt dumpGraphs; 34 | 35 | bool EPPEncode::doInitialization(Module &m) { return false; } 36 | bool EPPEncode::doFinalization(Module &m) { return false; } 37 | 38 | namespace { 39 | 40 | void printCFG(Function &F) { 41 | legacy::FunctionPassManager FPM(F.getParent()); 42 | FPM.add(llvm::createCFGPrinterLegacyPassPass()); 43 | FPM.doInitialization(); 44 | FPM.run(F); 45 | FPM.doFinalization(); 46 | } 47 | 48 | void dumpDotGraph(StringRef filename, const AuxGraph &AG) { 49 | error_code EC; 50 | raw_fd_ostream out(filename, EC, sys::fs::F_Text); 51 | AG.dot(out); 52 | out.close(); 53 | } 54 | } 55 | 56 | bool EPPEncode::runOnFunction(Function &F) { 57 | LI = &getAnalysis().getLoopInfo(); 58 | encode(F); 59 | return false; 60 | } 61 | 62 | void EPPEncode::releaseMemory() { 63 | LI = nullptr; 64 | numPaths.clear(); 65 | AG.clear(); 66 | } 67 | 68 | void postorderHelper(BasicBlock *toVisit, vector &blocks, 69 | DenseSet &seen, 70 | const set &SCCBlocks) { 71 | seen.insert(toVisit); 72 | for (auto s = succ_begin(toVisit), e = succ_end(toVisit); s != e; ++s) { 73 | 74 | // Don't need to worry about backedge successors as their targets 75 | // will be visited already and will fail the first condition check. 76 | 77 | if (!seen.count(*s) && (SCCBlocks.find(*s) != SCCBlocks.end())) { 78 | postorderHelper(*s, blocks, seen, SCCBlocks); 79 | } 80 | } 81 | blocks.push_back(toVisit); 82 | } 83 | 84 | vector postOrder(BasicBlock *Block, 85 | const set &SCCBlocks) { 86 | vector ordered; 87 | DenseSet seen; 88 | postorderHelper(Block, ordered, seen, SCCBlocks); 89 | return ordered; 90 | } 91 | 92 | vector postOrder(Function &F) { 93 | vector PostOrderBlocks; 94 | 95 | // Add all the basicblocks in the function to a set. 96 | SetVector BasicBlocks; 97 | for (auto &BB : F) 98 | BasicBlocks.insert(&BB); 99 | 100 | for (auto I = scc_begin(&F), IE = scc_end(&F); I != IE; ++I) { 101 | 102 | // Obtain the vector of BBs 103 | const std::vector &SCCBBs = *I; 104 | 105 | // Find an entry block into the current SCC as the starting point 106 | // of the DFS for the postOrder traversal. Now the *entry* block 107 | // should have predecessors in other SCC's which are topologically 108 | // before this SCC, i.e blocks not seen yet. 109 | 110 | // Remove each basic block which we encounter in the current SCC. 111 | // Remaining blocks must be topologically earlier than the blocks 112 | // we have seen already. 113 | DEBUG(errs() << "SCC: "); 114 | for (auto *BB : SCCBBs) { 115 | DEBUG(errs() << BB->getName() << " "); 116 | BasicBlocks.remove(BB); 117 | } 118 | DEBUG(errs() << "\n"); 119 | 120 | // Find the first block in the current SCC to have a predecessor 121 | // in the remaining blocks. This becomes the starting block for the DFS 122 | // Exception: SCC size = 1. 123 | 124 | BasicBlock *Start = nullptr; 125 | 126 | for (int i = 0; i < SCCBBs.size() && Start == nullptr; i++) { 127 | auto BB = SCCBBs[i]; 128 | for (auto P = pred_begin(BB), E = pred_end(BB); P != E; P++) { 129 | if (BasicBlocks.count(*P)) { 130 | Start = BB; 131 | break; 132 | } 133 | } 134 | } 135 | 136 | if (!Start) { 137 | Start = SCCBBs[0]; 138 | assert(SCCBBs.size() == 1 && 139 | "Should be entry block only which has no preds"); 140 | } 141 | 142 | set SCCBlocksSet(SCCBBs.begin(), SCCBBs.end()); 143 | auto blocks = postOrder(Start, SCCBlocksSet); 144 | 145 | assert(SCCBBs.size() == blocks.size() && 146 | "Could not discover all blocks"); 147 | 148 | for (auto *BB : blocks) { 149 | PostOrderBlocks.push_back(BB); 150 | } 151 | } 152 | 153 | DEBUG(errs() << "Post Order Blocks: \n"); 154 | for (auto &POB : PostOrderBlocks) 155 | DEBUG(errs() << POB->getName() << " "); 156 | DEBUG(errs() << "\n"); 157 | 158 | return PostOrderBlocks; 159 | } 160 | 161 | DenseSet> 162 | getBackEdges(BasicBlock *StartBB) { 163 | SmallVector, 8> 164 | BackEdgesVec; 165 | FindFunctionBackedges(*StartBB->getParent(), BackEdgesVec); 166 | DenseSet> BackEdges; 167 | 168 | for (auto &BE : BackEdgesVec) { 169 | BackEdges.insert(BE); 170 | } 171 | return BackEdges; 172 | } 173 | 174 | void EPPEncode::encode(Function &F) { 175 | DEBUG(errs() << "Called Encode on " << F.getName() << "\n"); 176 | 177 | AG.init(F); 178 | 179 | auto *Entry = &F.getEntryBlock(); 180 | auto BackEdges = getBackEdges(Entry); 181 | 182 | SetVector> SegmentEdges; 183 | 184 | for (auto &BB : AG.nodes()) { 185 | for (auto S = succ_begin(BB), E = succ_end(BB); S != E; S++) { 186 | if (BackEdges.count(make_pair(BB, *S)) || 187 | LI->getLoopFor(BB) != LI->getLoopFor(*S)) { 188 | SegmentEdges.insert({BB, *S}); 189 | } 190 | } 191 | } 192 | 193 | if (dumpGraphs) { 194 | dumpDotGraph("auxgraph-1.dot", AG); 195 | } 196 | 197 | AG.segment(SegmentEdges); 198 | 199 | if (dumpGraphs) { 200 | dumpDotGraph("auxgraph-2.dot", AG); 201 | } 202 | 203 | for (auto &B : AG.nodes()) { 204 | APInt pathCount(64, 0, true); 205 | 206 | auto Succs = AG.succs(B); 207 | if (Succs.empty()) { 208 | pathCount = 1; 209 | assert( 210 | B->getName().startswith("fake.exit") && 211 | "The only block without a successor should be the fake exit"); 212 | } else { 213 | for (auto &SE : Succs) { 214 | AG[SE] = pathCount; 215 | auto *S = SE->tgt; 216 | if (numPaths.count(S) == 0) 217 | numPaths.insert(make_pair(S, APInt(64, 0, true))); 218 | 219 | // This is the only place we need to check for overflow. 220 | // If there is an overflow, indicate this by saving 0 as the 221 | // number of paths from the entry block. This is impossible for 222 | // a regular CFG where the numpaths from entry would atleast be 223 | // 1 224 | // if the entry block is also the exit block. 225 | bool Ov = false; 226 | pathCount = pathCount.sadd_ov(numPaths[S], Ov); 227 | if (Ov) { 228 | numPaths.clear(); 229 | numPaths.insert(make_pair(Entry, APInt(64, 0, true))); 230 | DEBUG(errs() 231 | << "Integer Overflow in function " << F.getName()); 232 | return; 233 | } 234 | } 235 | } 236 | 237 | numPaths.insert({B, pathCount}); 238 | } 239 | 240 | if (dumpGraphs) { 241 | dumpDotGraph("auxgraph-3.dot", AG); 242 | } 243 | } 244 | 245 | char EPPEncode::ID = 0; 246 | static RegisterPass X("", "EPPEncode"); 247 | -------------------------------------------------------------------------------- /lib/epp/EPPPathPrinter.cpp: -------------------------------------------------------------------------------- 1 | #define DEBUG_TYPE "epp_pathprinter" 2 | #include "llvm/ADT/SmallString.h" 3 | #include "llvm/Analysis/LoopInfo.h" 4 | #include "llvm/IR/BasicBlock.h" 5 | #include "llvm/IR/CallSite.h" 6 | #include "llvm/IR/Constants.h" 7 | #include "llvm/IR/DebugInfo.h" 8 | #include "llvm/IR/Instructions.h" 9 | #include "llvm/Support/Debug.h" 10 | #include "llvm/Support/raw_ostream.h" 11 | 12 | #include 13 | #include 14 | 15 | #include "EPPDecode.h" 16 | #include "EPPPathPrinter.h" 17 | 18 | using namespace llvm; 19 | using namespace epp; 20 | using namespace std; 21 | 22 | extern cl::opt profile; 23 | 24 | bool EPPPathPrinter::doInitialization(Module &M) { 25 | uint32_t Id = 0; 26 | for (auto &F : M) { 27 | FunctionIdToPtr[Id++] = &F; 28 | } 29 | return false; 30 | } 31 | 32 | void printPathSrc(vector &blocks, raw_ostream &out, 33 | SmallString<8> prefix) { 34 | unsigned line = 0; 35 | llvm::StringRef file; 36 | for (auto *bb : blocks) { 37 | for (auto &instruction : *bb) { 38 | MDNode *n = instruction.getMetadata("dbg"); 39 | if (!n) { 40 | continue; 41 | } 42 | DebugLoc Loc(n); 43 | if (Loc->getLine() != line || Loc->getFilename() != file) { 44 | line = Loc->getLine(); 45 | file = Loc->getFilename(); 46 | out << prefix << "- " << file.str() << "," << line << "\n"; 47 | } 48 | } 49 | } 50 | } 51 | 52 | bool EPPPathPrinter::runOnModule(Module &M) { 53 | 54 | EPPDecode &D = getAnalysis(); 55 | 56 | ifstream InFile(profile.c_str(), ios::in); 57 | assert(InFile.is_open() && "Could not open file for reading"); 58 | 59 | errs() << "# Decoded Paths\n"; 60 | 61 | try { 62 | string Line; 63 | while (getline(InFile, Line)) { 64 | uint64_t FunctionId = 0, NumberOfPaths = 0; 65 | stringstream SS(Line); 66 | SS >> FunctionId >> NumberOfPaths; 67 | 68 | // If no paths have been executed for this function, 69 | // then skip it altogether. A continue over here is fine, 70 | // since there are no lines for the paths themselves and 71 | // the next line we expect is for one FunctionId and NumberOfPaths. 72 | 73 | if (NumberOfPaths == 0) 74 | continue; 75 | 76 | errs() << "- name: " << FunctionIdToPtr[FunctionId]->getName() 77 | << "\n"; 78 | errs() << " num_exec_paths: " << NumberOfPaths << "\n"; 79 | 80 | vector Paths; 81 | for (uint32_t I = 0; I < NumberOfPaths; I++) { 82 | getline(InFile, Line); 83 | 84 | stringstream SS(Line); 85 | string PathIdStr; 86 | uint64_t PathExecFreq; 87 | SS >> PathIdStr >> PathExecFreq; 88 | APInt PathId(64, StringRef(PathIdStr), 16); 89 | 90 | // Add a path data struct for each path we find in the 91 | // profile. For each struct only initialize the Id and 92 | // Frequency fields. 93 | Path P = {PathId, PathExecFreq}; 94 | D.getPathInfo(FunctionId, P); 95 | Paths.push_back(P); 96 | } 97 | 98 | // Sort the paths in descending order of their frequency 99 | // If the frequency is same, descending order of id (id cannot be 100 | // same) 101 | sort(Paths.begin(), Paths.end(), 102 | [](const Path &P1, const Path &P2) { 103 | return (P1.Freq > P2.Freq) || 104 | (P1.Freq == P2.Freq && P1.Id.uge(P2.Id)); 105 | }); 106 | 107 | for (auto &P : Paths) { 108 | SmallString<16> PathId; 109 | P.Id.toStringSigned(PathId, 16); 110 | errs() << " - path: " << PathId << "\n"; 111 | printPathSrc(P.Blocks, errs(), StringRef(" ")); 112 | } 113 | } 114 | } catch (...) { 115 | report_fatal_error("Invalid profile format?"); 116 | } 117 | 118 | InFile.close(); 119 | 120 | return false; 121 | } 122 | 123 | char EPPPathPrinter::ID = 0; 124 | -------------------------------------------------------------------------------- /lib/epp/EPPProfile.cpp: -------------------------------------------------------------------------------- 1 | #define DEBUG_TYPE "epp_profile" 2 | #include "llvm/ADT/ArrayRef.h" 3 | #include "llvm/ADT/SmallVector.h" 4 | #include "llvm/ADT/Statistic.h" 5 | #include "llvm/Analysis/CFG.h" 6 | //#include "llvm/Bitcode/ReaderWriter.h" 7 | #include "llvm/Bitcode/BitcodeWriter.h" 8 | #include "llvm/IR/BasicBlock.h" 9 | #include "llvm/IR/CallSite.h" 10 | #include "llvm/IR/DerivedTypes.h" 11 | #include "llvm/IR/Dominators.h" 12 | #include "llvm/IR/IRBuilder.h" 13 | #include "llvm/IR/InstrTypes.h" 14 | #include "llvm/IR/Instruction.h" 15 | #include "llvm/IR/Instructions.h" 16 | #include "llvm/Support/Debug.h" 17 | #include "llvm/Support/FileSystem.h" 18 | #include "llvm/Support/GraphWriter.h" 19 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 20 | #include "llvm/Transforms/Utils/ModuleUtils.h" 21 | 22 | #include "EPPEncode.h" 23 | #include "EPPProfile.h" 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | using namespace llvm; 30 | using namespace epp; 31 | using namespace std; 32 | 33 | extern cl::opt profileOutputFilename; 34 | 35 | bool EPPProfile::doInitialization(Module &M) { 36 | uint32_t Id = 0; 37 | for (auto &F : M) { 38 | FunctionIds[&F] = Id++; 39 | } 40 | 41 | return false; 42 | } 43 | 44 | bool EPPProfile::doFinalization(Module &M) { return false; } 45 | 46 | namespace { 47 | 48 | uint64_t NumInstInc = 0; 49 | uint64_t NumInstLog = 0; 50 | 51 | void saveModule(Module &m, StringRef filename) { 52 | error_code EC; 53 | raw_fd_ostream out(filename.data(), EC, sys::fs::F_None); 54 | 55 | if (EC) { 56 | report_fatal_error("error saving llvm module to '" + filename + 57 | "': \n" + EC.message()); 58 | } 59 | WriteBitcodeToFile(&m, out); 60 | } 61 | 62 | SmallVector getFunctionExitBlocks(Function &F) { 63 | SmallVector R; 64 | for (auto &BB : F) { 65 | if (BB.getTerminator()->getNumSuccessors() == 0) { 66 | R.push_back(&BB); 67 | } 68 | } 69 | return R; 70 | } 71 | 72 | void insertInc(BasicBlock *Block, APInt Inc, AllocaInst *Ctr) { 73 | if (Inc.ne(APInt(64, 0, true))) { 74 | //(errs() << "Inserting Increment " << Increment << " " 75 | //<< addPos->getParent()->getName() << "\n"); 76 | auto *addPos = &*Block->getFirstInsertionPt(); 77 | auto *LI = new LoadInst(Ctr, "ld.epp.ctr", addPos); 78 | 79 | Constant *CI = 80 | ConstantInt::getIntegerValue(Ctr->getAllocatedType(), Inc); 81 | auto *BI = BinaryOperator::CreateAdd(LI, CI); 82 | BI->insertAfter(LI); 83 | (new StoreInst(BI, Ctr))->insertAfter(BI); 84 | 85 | ++NumInstInc; 86 | } 87 | } 88 | 89 | BasicBlock *interpose(BasicBlock *BB, BasicBlock *Succ, 90 | DominatorTree *DT = nullptr, LoopInfo *LI = nullptr) { 91 | 92 | unsigned SuccNum = GetSuccessorNumber(BB, Succ); 93 | 94 | // If this is a critical edge, let SplitCriticalEdge do it. (This does 95 | // not deal with critical edges which terminate at ehpads) 96 | TerminatorInst *LatchTerm = BB->getTerminator(); 97 | if (SplitCriticalEdge( 98 | LatchTerm, SuccNum, 99 | CriticalEdgeSplittingOptions(DT, LI).setPreserveLCSSA())) { 100 | return LatchTerm->getSuccessor(SuccNum); 101 | } 102 | 103 | // If the edge isn't critical, then BB has a single successor or Succ has a 104 | // single pred. Insert a new block or split the pred block. 105 | if (BasicBlock *SP = Succ->getSinglePredecessor()) { 106 | assert(SP == BB && "CFG broken"); 107 | auto *New = BasicBlock::Create( 108 | BB->getContext(), BB->getName() + ".intp", BB->getParent()); 109 | 110 | BB->getTerminator()->replaceUsesOfWith(Succ, New); 111 | BranchInst::Create(Succ, New); 112 | 113 | // Hoist all special instructions from the Tgt block 114 | // to the new block. Rewrite the uses of the old instructions 115 | // to use the instructions in the new block. This is used when the 116 | // edge being split has ehpad destination. 117 | 118 | for (auto &I : vector( 119 | Succ->begin(), Succ->getFirstInsertionPt())) { 120 | I->moveBefore(New->getTerminator()); 121 | } 122 | 123 | return New; 124 | } 125 | 126 | // Otherwise, if BB has a single successor, successorsplit it at the bottom 127 | // of the block. 128 | assert(BB->getTerminator()->getNumSuccessors() == 1 && 129 | "Should have a single succ!"); 130 | return SplitBlock(BB, BB->getTerminator(), DT, LI); 131 | } 132 | 133 | void insertLogPath(BasicBlock *BB, uint64_t FuncId, AllocaInst *Ctr, 134 | Constant *Zap) { 135 | 136 | //errs() << "Inserting Log: " << BB->getName() << "\n"; 137 | //errs() << *BB << "\n"; 138 | 139 | Module *M = BB->getModule(); 140 | auto &Ctx = M->getContext(); 141 | auto *voidTy = Type::getVoidTy(Ctx); 142 | auto *CtrTy = Ctr->getAllocatedType(); 143 | auto *FIdArg = ConstantInt::getIntegerValue(CtrTy, APInt(64, FuncId, true)); 144 | Function *logFun2 = cast( 145 | M->getOrInsertFunction("__epp_logPath", voidTy, CtrTy, CtrTy)); 146 | 147 | 148 | // We insert the logging function as the first thing in the basic block 149 | // as we know for sure that there is no other instrumentation present in 150 | // this basic block. 151 | Instruction *logPos = &*BB->getFirstInsertionPt(); 152 | auto *LI = new LoadInst(Ctr, "ld.epp.ctr", logPos); 153 | vector Params = {LI, FIdArg}; 154 | auto *CI = CallInst::Create(logFun2, Params, ""); 155 | CI->insertAfter(LI); 156 | (new StoreInst(Zap, Ctr))->insertAfter(CI); 157 | 158 | 159 | ++NumInstLog; 160 | } 161 | 162 | } 163 | 164 | void EPPProfile::addCtorsAndDtors(Module &Mod) { 165 | auto &Ctx = Mod.getContext(); 166 | auto *voidTy = Type::getVoidTy(Ctx); 167 | auto *int32Ty = Type::getInt32Ty(Ctx); 168 | auto *int8PtrTy = Type::getInt8PtrTy(Ctx, 0); 169 | uint32_t NumberOfFunctions = FunctionIds.size(); 170 | 171 | auto *EPPInit = cast( 172 | Mod.getOrInsertFunction("__epp_init", voidTy, int32Ty)); 173 | auto *EPPSave = cast( 174 | Mod.getOrInsertFunction("__epp_save", voidTy, int8PtrTy)); 175 | 176 | // Add Global Constructor for initializing path profiling 177 | auto *EPPInitCtor = 178 | cast(Mod.getOrInsertFunction("__epp_ctor", voidTy)); 179 | auto *CtorBB = BasicBlock::Create(Ctx, "entry", EPPInitCtor); 180 | auto *Arg = ConstantInt::get(int32Ty, NumberOfFunctions, false); 181 | CallInst::Create(EPPInit, {Arg}, "", CtorBB); 182 | ReturnInst::Create(Ctx, CtorBB); 183 | appendToGlobalCtors(Mod, EPPInitCtor, 0); 184 | 185 | auto *Number = ConstantInt::get(int32Ty, NumberOfFunctions, false); 186 | new GlobalVariable(Mod, Number->getType(), false, 187 | GlobalValue::ExternalLinkage, Number, 188 | "__epp_numberOfFunctions"); 189 | 190 | // Add global destructor to dump out results 191 | auto *EPPSaveDtor = 192 | cast(Mod.getOrInsertFunction("__epp_dtor", voidTy)); 193 | auto *DtorBB = BasicBlock::Create(Ctx, "entry", EPPSaveDtor); 194 | IRBuilder<> Builder(DtorBB); 195 | Builder.CreateCall( 196 | EPPSave, 197 | {Builder.CreateGlobalStringPtr(profileOutputFilename.getValue())}); 198 | Builder.CreateRet(nullptr); 199 | 200 | appendToGlobalDtors(Mod, cast(EPPSaveDtor), 0); 201 | } 202 | 203 | bool EPPProfile::runOnModule(Module &Mod) { 204 | DEBUG(errs() << "Running Profile\n"); 205 | 206 | errs() << "# Instrumented Functions\n"; 207 | 208 | for (auto &F : Mod) { 209 | if (F.isDeclaration()) 210 | continue; 211 | 212 | auto &Enc = getAnalysis(F); 213 | auto NumPaths = Enc.numPaths[&F.getEntryBlock()]; 214 | 215 | errs() << "- name: " << F.getName() << "\n"; 216 | errs() << " num_paths: " << NumPaths << "\n"; 217 | // Check if integer overflow occurred during path enumeration, 218 | // if it did then the entry block numpaths is set to zero. 219 | if (NumPaths.ne(APInt(64, 0, true))) { 220 | instrument(F, Enc); 221 | errs() << " num_inst_inc: " << NumInstInc << "\n"; 222 | errs() << " num_inst_log: " << NumInstLog << "\n"; 223 | } 224 | } 225 | 226 | addCtorsAndDtors(Mod); 227 | 228 | return true; 229 | } 230 | 231 | /// This routine inserts two types of instrumentation. 232 | /// 1. Incrementing a counter along a set of edges 233 | /// 2. Logging the value of the counter at certain blocks. 234 | /// For 1) The counter is incremented by splitting an existing 235 | /// edge in the CFG. This implies a new basic block is inserted 236 | /// between two basic blocks and the instrumentation is inserted 237 | /// into the new block. 238 | /// For 2) The counter value is saved by the runtim at certain 239 | /// basic blocks. This is performed by the insertion of function 240 | /// call to the logging runtime function. 241 | /// Goals: 242 | /// 1) Splitting edges should insert *new* blocks inside them so 243 | /// that the Graph structure which maintains the edge weights does 244 | /// not need to be updated at runtime. 245 | /// 2) Instrumentation is always inserted at the BB's first insertion pt. 246 | /// 3) There is an ordering on the the instrumentation insertion. 247 | /// - splitting edges 248 | /// - leaf log function calls 249 | /// - counter allocation 250 | void EPPProfile::instrument(Function &F, EPPEncode &Enc) { 251 | NumInstInc = 0, NumInstLog = 0; 252 | 253 | Module *M = F.getParent(); 254 | auto &Ctx = M->getContext(); 255 | uint64_t FuncId = FunctionIds[&F]; 256 | const DataLayout& DL = M->getDataLayout(); 257 | 258 | // Allocate a counter but dont insert it just yet. We want the 259 | // counter to be the last thing to insert in the function so that 260 | // it always dominates the log function call -- eg. when there is 261 | // only 1 basic block in the function. 262 | Type *CtrTy = Type::getInt64Ty(Ctx); 263 | Constant *Zap = ConstantInt::getIntegerValue(CtrTy, APInt(64, 0, true)); 264 | auto *Ctr = new AllocaInst(CtrTy, DL.getAllocaAddrSpace(), nullptr, "epp.ctr"); 265 | 266 | auto ExitBlocks = getFunctionExitBlocks(F); 267 | 268 | // Get all the non-zero real edges to instrument 269 | const auto &Wts = Enc.AG.getWeights(); 270 | 271 | // Enc.AG.printWeights(); 272 | 273 | for (auto &W : Wts) { 274 | auto &Ptr = W.first; 275 | BasicBlock *Src = Ptr->src, *Tgt = Ptr->tgt; 276 | BasicBlock *N = interpose(Src, Tgt); 277 | insertInc(N, W.second, Ctr); 278 | } 279 | 280 | // Get the weights for the segmented edges 281 | const auto &SegMap = Enc.AG.getSegmentMap(); 282 | 283 | for (auto &S : SegMap) { 284 | auto &Ptr = S.first; 285 | BasicBlock *Src = Ptr->src, *Tgt = Ptr->tgt; 286 | 287 | auto &AExit = S.second.first; 288 | APInt Pre = Enc.AG.getEdgeWeight(AExit); 289 | auto &EntryB = S.second.second; 290 | APInt Post = Enc.AG.getEdgeWeight(EntryB); 291 | 292 | BasicBlock *N = interpose(Src, Tgt); 293 | 294 | // Since we always add instrumentation 295 | insertInc(N, Post, Ctr); 296 | insertLogPath(N, FuncId, Ctr, Zap); 297 | insertInc(N, Pre, Ctr); 298 | } 299 | 300 | // Add the logpath function for all function exiting 301 | // basic blocks. 302 | for (auto &EB : ExitBlocks) { 303 | insertLogPath(EB, FuncId, Ctr, Zap); 304 | } 305 | 306 | // Add the counter as the first instruction in the entry 307 | // block of the function. Set the counter to zero. 308 | Ctr->insertBefore(&*F.getEntryBlock().getFirstInsertionPt()); 309 | auto *SI = new StoreInst(Zap, Ctr); 310 | SI->insertAfter(Ctr); 311 | 312 | // saveModule(*M, "test.bc"); 313 | } 314 | 315 | char EPPProfile::ID = 0; 316 | -------------------------------------------------------------------------------- /lib/epp/Runtime.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | #define EPP(X) __epp_##X 15 | 16 | extern uint32_t EPP(numberOfFunctions); 17 | 18 | typedef vector> TLSDataTy; 19 | list> GlobalEPPDataList; 20 | 21 | mutex tlsMutex; 22 | 23 | class EPP(data) { 24 | shared_ptr Ptr; 25 | 26 | public: 27 | void log(uint64_t Val, uint64_t FunctionId) { 28 | // cout << "log " << tid << " " << Val << " " << FunctionId << endl; 29 | (*Ptr)[FunctionId][Val] += 1; 30 | } 31 | 32 | EPP(data)() { 33 | lock_guard lock(tlsMutex); 34 | Ptr = make_shared(); 35 | GlobalEPPDataList.push_back(Ptr); 36 | // Allocate an unordered_map for each function even though we know it 37 | // may not 38 | // be used. This is to make the lookup faster at runtime. 39 | Ptr->resize(EPP(numberOfFunctions)); 40 | } 41 | }; 42 | 43 | /// Why is this unique_ptr? 44 | /// 45 | 46 | thread_local unique_ptr Data = make_unique(); 47 | 48 | extern "C" { 49 | 50 | void EPP(init)() {} 51 | 52 | void EPP(logPath)(uint64_t Val, uint64_t FunctionId) { 53 | if (Data) 54 | Data->log(Val, FunctionId); 55 | } 56 | 57 | void EPP(save)(char *path) { 58 | 59 | FILE *fp = fopen(path, "w"); 60 | 61 | // TODO: Modify to enable option of per thread dump 62 | 63 | TLSDataTy Accumulate(EPP(numberOfFunctions)); 64 | 65 | for (auto T : GlobalEPPDataList) { 66 | for (uint32_t I = 0; I < T->size(); I++) { 67 | for (auto &KV : T->at(I)) { 68 | Accumulate[I][KV.first] += KV.second; 69 | } 70 | } 71 | } 72 | 73 | // Save the data to a file. Make the dump deterministic by 74 | // sorting the function ids, and then sorting the paths by 75 | // their freq/id. The path printer already sorts by freq. 76 | 77 | for (uint32_t I = 0; I < Accumulate.size(); I++) { 78 | if (Accumulate[I].size() > 0) { 79 | fprintf(fp, "%u %lu\n", I, Accumulate[I].size()); 80 | vector> Values(Accumulate[I].begin(), 81 | Accumulate[I].end()); 82 | sort(Values.begin(), Values.end(), 83 | [](const pair &P1, 84 | const pair &P2) { 85 | return (P1.second > P2.second) || 86 | (P1.second == P2.second && P1.first > P2.first); 87 | }); 88 | for (auto &KV : Values) { 89 | fprintf(fp, "%016" PRIx64 " %" PRIu64 "\n", KV.first, 90 | KV.second); 91 | } 92 | } 93 | } 94 | 95 | fclose(fp); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /lib/epp/SplitLandingPadPredsPass.cpp: -------------------------------------------------------------------------------- 1 | #include "SplitLandingPadPredsPass.h" 2 | #include "llvm/IR/Instructions.h" 3 | #include "llvm/IR/Module.h" 4 | #include "llvm/Support/raw_ostream.h" 5 | #include "llvm/Transforms/IPO.h" 6 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 7 | 8 | using namespace epp; 9 | 10 | namespace { 11 | 12 | void SplitLandingPadPreds(Function &F) { 13 | for (auto &BB : F) { 14 | for (auto &I : BB) { 15 | if (InvokeInst *II = dyn_cast(&I)) { 16 | BasicBlock *LPad = II->getUnwindDest(); 17 | 18 | // Check if BB->LPad edge is a critical edge. 19 | if (BB.getSingleSuccessor() || LPad->getUniquePredecessor()) 20 | continue; 21 | 22 | SmallVector NewBBs; 23 | SplitLandingPadPredecessors(LPad, &BB, ".1", ".2", NewBBs); 24 | } 25 | } 26 | } 27 | } 28 | } 29 | 30 | bool SplitLandingPadPredsPass::runOnModule(Module &M) { 31 | for (auto &F : M) { 32 | if (F.isDeclaration()) 33 | continue; 34 | SplitLandingPadPreds(F); 35 | } 36 | 37 | return true; 38 | } 39 | 40 | char SplitLandingPadPredsPass::ID = 0; 41 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # For some reason this part of the LLVM scripts uses DIR instead of DIRS 3 | set(LLVM_LIBRARY_DIR ${LLVM_LIBRARY_DIRS}) 4 | 5 | file(COPY lit.cfg srcs DESTINATION ${CMAKE_BINARY_DIR}/test) 6 | 7 | configure_lit_site_cfg( 8 | ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in 9 | ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg 10 | ) 11 | 12 | 13 | # Set the depends list as a variable so that it can grow conditionally. 14 | # NOTE: Sync the substitutions in test/lit.cfg when adding to this list. 15 | set(LLVM_TEST_DEPENDS 16 | llvm-epp 17 | epp-rt 18 | ) 19 | 20 | add_lit_testsuite(check-epp "Running regression tests" 21 | ${CMAKE_CURRENT_BINARY_DIR} 22 | PARAMS llvm_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg 23 | llvm_unit_site_config=${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg 24 | DEPENDS ${LLVM_TEST_DEPENDS} 25 | ) 26 | set_target_properties(check-epp PROPERTIES FOLDER "Tests") 27 | 28 | add_lit_testsuites(epp-test ${CMAKE_CURRENT_SOURCE_DIR} 29 | PARAMS llvm_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg 30 | DEPENDS ${LLVM_TEST_DEPENDS} 31 | ) 32 | 33 | # Setup a legacy alias for 'check-llvm'. This will likely change to be an 34 | # alias for 'check-all' at some point in the future. 35 | add_custom_target(check) 36 | add_dependencies(check check-epp) 37 | set_target_properties(check PROPERTIES FOLDER "Tests") 38 | -------------------------------------------------------------------------------- /test/lit.cfg: -------------------------------------------------------------------------------- 1 | # -*- Python -*- 2 | 3 | # Configuration file for the 'lit' test runner. 4 | 5 | import os 6 | import sys 7 | import re 8 | import platform 9 | 10 | import lit.util 11 | import lit.formats 12 | 13 | # name: The name of this test suite. 14 | config.name = 'epp-test' 15 | 16 | # Tweak PATH for Win32 to decide to use bash.exe or not. 17 | if sys.platform in ['win32']: 18 | # Seek sane tools in directories and set to $PATH. 19 | path = getattr(config, 'lit_tools_dir', None) 20 | path = lit_config.getToolsPath(path, 21 | config.environment['PATH'], 22 | ['cmp.exe', 'grep.exe', 'sed.exe']) 23 | if path is not None: 24 | path = os.path.pathsep.join((path, 25 | config.environment['PATH'])) 26 | config.environment['PATH'] = path 27 | 28 | # Choose between lit's internal shell pipeline runner and a real shell. If 29 | # LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override. 30 | use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL") 31 | if use_lit_shell: 32 | # 0 is external, "" is default, and everything else is internal. 33 | execute_external = (use_lit_shell == "0") 34 | else: 35 | # Otherwise we default to internal on Windows and external elsewhere, as 36 | # bash on Windows is usually very slow. 37 | execute_external = (not sys.platform in ['win32']) 38 | 39 | # testFormat: The test format to use to interpret tests. 40 | config.test_format = lit.formats.ShTest(execute_external) 41 | 42 | # suffixes: A list of file extensions to treat as test files. This is overriden 43 | # by individual lit.local.cfg files in the test subdirectories. 44 | config.suffixes = ['.ll', '.c', '.cxx'] 45 | 46 | # excludes: A list of directories to exclude from the testsuite. The 'Inputs' 47 | # subdirectories contain auxiliary inputs for various tests in their parent 48 | # directories. 49 | config.excludes = ['Inputs', 'CMakeLists.txt', 'CMakeFiles'] 50 | 51 | # test_source_root: The root path where tests are located. 52 | config.test_source_root = os.path.dirname(__file__) 53 | 54 | # test_exec_root: The root path where tests should be run. 55 | llvm_obj_root = getattr(config, 'llvm_obj_root', None) 56 | if llvm_obj_root is not None: 57 | config.test_exec_root = os.path.join(llvm_obj_root, 'test') 58 | 59 | # Tweak the PATH to include the tools dir. 60 | if llvm_obj_root is not None: 61 | llvm_tools_dir = getattr(config, 'llvm_tools_dir', None) 62 | if not llvm_tools_dir: 63 | lit_config.fatal('No LLVM tools dir set!') 64 | path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH'])) 65 | config.environment['PATH'] = path 66 | 67 | # Add the project binary dir 68 | config.environment['PATH'] = os.path.pathsep.join((config.project_binary_dir, \ 69 | config.environment['PATH'])) 70 | 71 | # Add the project library dir 72 | if not 'LD_LIBRARY_PATH' in config.environment: 73 | config.environment['LD_LIBRARY_PATH'] = '' 74 | 75 | config.environment['LD_LIBRARY_PATH'] = os.path.pathsep.join((config.project_library_dir, \ 76 | config.environment['LD_LIBRARY_PATH'])) 77 | 78 | 79 | if not 'LIBRARY_PATH' in config.environment: 80 | config.environment['LIBRARY_PATH'] = '' 81 | 82 | config.environment['LIBRARY_PATH'] = os.path.pathsep.join((config.project_library_dir, \ 83 | config.environment['LIBRARY_PATH'])) 84 | 85 | 86 | # Propagate 'HOME' through the environment. 87 | if 'HOME' in os.environ: 88 | config.environment['HOME'] = os.environ['HOME'] 89 | 90 | # Propagate 'INCLUDE' through the environment. 91 | if 'INCLUDE' in os.environ: 92 | config.environment['INCLUDE'] = os.environ['INCLUDE'] 93 | 94 | # Propagate 'LIB' through the environment. 95 | if 'LIB' in os.environ: 96 | config.environment['LIB'] = os.environ['LIB'] 97 | 98 | # Propagate the temp directory. Windows requires this because it uses \Windows\ 99 | # if none of these are present. 100 | if 'TMP' in os.environ: 101 | config.environment['TMP'] = os.environ['TMP'] 102 | if 'TEMP' in os.environ: 103 | config.environment['TEMP'] = os.environ['TEMP'] 104 | 105 | # Propagate LLVM_SRC_ROOT into the environment. 106 | config.environment['LLVM_SRC_ROOT'] = getattr(config, 'llvm_src_root', '') 107 | 108 | # Propagate PYTHON_EXECUTABLE into the environment 109 | config.environment['PYTHON_EXECUTABLE'] = getattr(config, 'python_executable', 110 | '') 111 | 112 | # Propagate path to symbolizer for ASan/MSan. 113 | for symbolizer in ['ASAN_SYMBOLIZER_PATH', 'MSAN_SYMBOLIZER_PATH']: 114 | if symbolizer in os.environ: 115 | config.environment[symbolizer] = os.environ[symbolizer] 116 | 117 | # Set up OCAMLPATH to include newly built OCaml libraries. 118 | llvm_lib_dir = getattr(config, 'llvm_lib_dir', None) 119 | if llvm_lib_dir is None: 120 | if llvm_obj_root is not None: 121 | llvm_lib_dir = os.path.join(llvm_obj_root, 'lib') 122 | 123 | if llvm_lib_dir is not None: 124 | llvm_ocaml_lib = os.path.join(llvm_lib_dir, 'ocaml') 125 | if llvm_ocaml_lib is not None: 126 | if 'OCAMLPATH' in os.environ: 127 | ocamlpath = os.path.pathsep.join((llvm_ocaml_lib, os.environ['OCAMLPATH'])) 128 | config.environment['OCAMLPATH'] = ocamlpath 129 | else: 130 | config.environment['OCAMLPATH'] = llvm_ocaml_lib 131 | 132 | if 'CAML_LD_LIBRARY_PATH' in os.environ: 133 | caml_ld_library_path = os.path.pathsep.join((llvm_ocaml_lib, 134 | os.environ['CAML_LD_LIBRARY_PATH'])) 135 | config.environment['CAML_LD_LIBRARY_PATH'] = caml_ld_library_path 136 | else: 137 | config.environment['CAML_LD_LIBRARY_PATH'] = llvm_ocaml_lib 138 | 139 | # Set up OCAMLRUNPARAM to enable backtraces in OCaml tests. 140 | config.environment['OCAMLRUNPARAM'] = 'b' 141 | 142 | ### 143 | 144 | import os 145 | 146 | # Check that the object root is known. 147 | if config.test_exec_root is None: 148 | # Otherwise, we haven't loaded the site specific configuration (the user is 149 | # probably trying to run on a test file directly, and either the site 150 | # configuration hasn't been created by the build system, or we are in an 151 | # out-of-tree build situation). 152 | 153 | # Check for 'llvm_site_config' user parameter, and use that if available. 154 | site_cfg = lit_config.params.get('llvm_site_config', None) 155 | if site_cfg and os.path.exists(site_cfg): 156 | lit_config.load_config(config, site_cfg) 157 | raise SystemExit 158 | 159 | # Try to detect the situation where we are using an out-of-tree build by 160 | # looking for 'llvm-config'. 161 | # 162 | # FIXME: I debated (i.e., wrote and threw away) adding logic to 163 | # automagically generate the lit.site.cfg if we are in some kind of fresh 164 | # build situation. This means knowing how to invoke the build system 165 | # though, and I decided it was too much magic. 166 | 167 | llvm_config = lit.util.which('llvm-config', config.environment['PATH']) 168 | if not llvm_config: 169 | lit_config.fatal('No site specific configuration available!') 170 | 171 | # Get the source and object roots. 172 | llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip() 173 | llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip() 174 | 175 | # Validate that we got a tree which points to here. 176 | this_src_root = os.path.dirname(config.test_source_root) 177 | if os.path.realpath(llvm_src_root) != os.path.realpath(this_src_root): 178 | lit_config.fatal('No site specific configuration available!') 179 | 180 | # Check that the site specific configuration exists. 181 | site_cfg = os.path.join(llvm_obj_root, 'test', 'lit.site.cfg') 182 | if not os.path.exists(site_cfg): 183 | lit_config.fatal('No site specific configuration available!') 184 | 185 | # Okay, that worked. Notify the user of the automagic, and reconfigure. 186 | lit_config.note('using out-of-tree build at %r' % llvm_obj_root) 187 | lit_config.load_config(config, site_cfg) 188 | raise SystemExit 189 | 190 | ### 191 | 192 | lli = 'lli' 193 | # The target triple used by default by lli is the process target triple (some 194 | # triple appropriate for generating code for the current process) but because 195 | # we don't support COFF in MCJIT well enough for the tests, force ELF format on 196 | # Windows. FIXME: the process target triple should be used here, but this is 197 | # difficult to obtain on Windows. 198 | if re.search(r'cygwin|mingw32|windows-gnu|windows-msvc|win32', config.host_triple): 199 | lli += ' -mtriple='+config.host_triple+'-elf' 200 | config.substitutions.append( ('%lli', lli ) ) 201 | 202 | # Similarly, have a macro to use llc with DWARF even when the host is win32. 203 | llc_dwarf = 'llc' 204 | if re.search(r'win32', config.target_triple): 205 | llc_dwarf += ' -mtriple='+config.target_triple.replace('-win32', '-mingw32') 206 | config.substitutions.append( ('%llc_dwarf', llc_dwarf) ) 207 | 208 | # Add site-specific substitutions. 209 | config.substitutions.append( ('%gold', config.gold_executable) ) 210 | config.substitutions.append( ('%ld64', config.ld64_executable) ) 211 | config.substitutions.append( ('%go', config.go_executable) ) 212 | config.substitutions.append( ('%llvmshlibdir', config.llvm_shlib_dir) ) 213 | config.substitutions.append( ('%shlibext', config.llvm_shlib_ext) ) 214 | config.substitutions.append( ('%exeext', config.llvm_exe_ext) ) 215 | config.substitutions.append( ('%python', config.python_executable) ) 216 | config.substitutions.append( ('%host_cc', config.host_cc) ) 217 | 218 | # OCaml substitutions. 219 | # Support tests for both native and bytecode builds. 220 | config.substitutions.append( ('%ocamlc', 221 | "%s ocamlc -cclib -L%s %s" % 222 | (config.ocamlfind_executable, llvm_lib_dir, config.ocaml_flags)) ) 223 | if config.have_ocamlopt in ('1', 'TRUE'): 224 | config.substitutions.append( ('%ocamlopt', 225 | "%s ocamlopt -cclib -L%s -cclib -Wl,-rpath,%s %s" % 226 | (config.ocamlfind_executable, llvm_lib_dir, llvm_lib_dir, config.ocaml_flags)) ) 227 | else: 228 | config.substitutions.append( ('%ocamlopt', "true" ) ) 229 | 230 | # For each occurrence of an llvm tool name as its own word, replace it 231 | # with the full path to the build directory holding that tool. This 232 | # ensures that we are testing the tools just built and not some random 233 | # tools that might happen to be in the user's PATH. Thus this list 234 | # includes every tool placed in $(LLVM_OBJ_ROOT)/$(BuildMode)/bin 235 | # (llvm_tools_dir in lit parlance). 236 | 237 | # Avoid matching RUN line fragments that are actually part of 238 | # path names or options or whatever. 239 | # The regex is a pre-assertion to avoid matching a preceding 240 | # dot, hyphen, carat, or slash (.foo, -foo, etc.). Some patterns 241 | # also have a post-assertion to not match a trailing hyphen (foo-). 242 | NOJUNK = r"(? %t.compile 8 | // RUN: %t-exec > %t.log 9 | // RUN: llvm-epp -p=%t.profile %t.bc 2> %t.decode 10 | // RUN: diff -aub %t.profile %s.txt 11 | -------------------------------------------------------------------------------- /test/srcs/01-basic.c.txt: -------------------------------------------------------------------------------- 1 | 0 1 2 | 0000000000000000 1 3 | -------------------------------------------------------------------------------- /test/srcs/02-triangle.c: -------------------------------------------------------------------------------- 1 | 2 | int main(int argc, char* argv[]) { 3 | if(argc > 2) { 4 | printf("This is a triangle"); 5 | } 6 | return 0; 7 | } 8 | 9 | // RUN: clang -c -g -emit-llvm %s -o %t.1.bc 10 | // RUN: opt -instnamer %t.1.bc -o %t.bc 11 | // RUN: llvm-epp %t.bc -o %t.profile 12 | // RUN: clang -v %t.epp.bc -o %t-exec -lepp-rt 2> %t.compile 13 | // RUN: %t-exec > %t.log 14 | // RUN: llvm-epp -p=%t.profile %t.bc 2> %t.decode 15 | // RUN: diff -aub %t.profile %s.txt 16 | -------------------------------------------------------------------------------- /test/srcs/02-triangle.c.txt: -------------------------------------------------------------------------------- 1 | 0 1 2 | 0000000000000001 1 3 | -------------------------------------------------------------------------------- /test/srcs/03-diamond.c: -------------------------------------------------------------------------------- 1 | 2 | int main(int argc, char* argv[]) { 3 | if(argc > 2) { 4 | printf("This is a triangle"); 5 | } 6 | else { 7 | printf("This is a diamond"); 8 | } 9 | return 0; 10 | } 11 | 12 | // RUN: clang -c -g -emit-llvm %s -o %t.1.bc 13 | // RUN: opt -instnamer %t.1.bc -o %t.bc 14 | // RUN: llvm-epp %t.bc -o %t.profile 15 | // RUN: clang -v %t.epp.bc -o %t-exec -lepp-rt 2> %t.compile 16 | // RUN: %t-exec > %t.log 17 | // RUN: llvm-epp -p=%t.profile %t.bc 2> %t.decode 18 | // RUN: diff -aub %t.profile %s.txt 19 | -------------------------------------------------------------------------------- /test/srcs/03-diamond.c.txt: -------------------------------------------------------------------------------- 1 | 0 1 2 | 0000000000000001 1 3 | -------------------------------------------------------------------------------- /test/srcs/04-diamond-x2.c: -------------------------------------------------------------------------------- 1 | 2 | int main(int argc, char* argv[]) { 3 | if(argc > 2) { 4 | printf("This is a triangle"); 5 | } 6 | else { 7 | printf("This is a diamond"); 8 | } 9 | if(argc > 4) { 10 | printf("This is a triangle x2"); 11 | } 12 | else { 13 | printf("This is a diamond x2"); 14 | } 15 | return 0; 16 | } 17 | 18 | // RUN: clang -c -g -emit-llvm %s -o %t.1.bc 19 | // RUN: opt -instnamer %t.1.bc -o %t.bc 20 | // RUN: llvm-epp %t.bc -o %t.profile 21 | // RUN: clang -v %t.epp.bc -o %t-exec -lepp-rt 2> %t.compile 22 | // RUN: %t-exec > %t.log 23 | // RUN: llvm-epp -p=%t.profile %t.bc 2> %t.decode 24 | // RUN: diff -aub %t.profile %s.txt 25 | -------------------------------------------------------------------------------- /test/srcs/04-diamond-x2.c.txt: -------------------------------------------------------------------------------- 1 | 0 1 2 | 0000000000000003 1 3 | -------------------------------------------------------------------------------- /test/srcs/05-loop.c: -------------------------------------------------------------------------------- 1 | 2 | int main(int argc, char* argv[]) { 3 | for(int i = 0; i < 10; i++) { 4 | printf("This is a loop"); 5 | } 6 | return 0; 7 | } 8 | 9 | // RUN: clang -c -g -emit-llvm %s -o %t.1.bc 10 | // RUN: opt -instnamer %t.1.bc -o %t.bc 11 | // RUN: llvm-epp %t.bc -o %t.profile 12 | // RUN: clang -v %t.epp.bc -o %t-exec -lepp-rt 2> %t.compile 13 | // RUN: %t-exec > %t.log 14 | // RUN: llvm-epp -p=%t.profile %t.bc 2> %t.decode 15 | // RUN: diff -aub %t.profile %s.txt 16 | -------------------------------------------------------------------------------- /test/srcs/05-loop.c.txt: -------------------------------------------------------------------------------- 1 | 0 5 2 | 0000000000000000 9 3 | 0000000000000004 1 4 | 0000000000000003 1 5 | 0000000000000002 1 6 | 0000000000000001 1 7 | -------------------------------------------------------------------------------- /test/srcs/06-loop-triangle.c: -------------------------------------------------------------------------------- 1 | 2 | int main(int argc, char* argv[]) { 3 | for(int i = 0; i < 10; i++) { 4 | if(i%2) { 5 | printf("This is a loop"); 6 | } 7 | } 8 | return 0; 9 | } 10 | 11 | // RUN: clang -c -g -emit-llvm %s -o %t.1.bc 12 | // RUN: opt -instnamer %t.1.bc -o %t.bc 13 | // RUN: llvm-epp %t.bc -o %t.profile 14 | // RUN: clang -v %t.epp.bc -o %t-exec -lepp-rt 2> %t.compile 15 | // RUN: %t-exec > %t.log 16 | // RUN: llvm-epp -p=%t.profile %t.bc 2> %t.decode 17 | // RUN: diff -aub %t.profile %s.txt 18 | -------------------------------------------------------------------------------- /test/srcs/06-loop-triangle.c.txt: -------------------------------------------------------------------------------- 1 | 0 6 2 | 0000000000000000 5 3 | 0000000000000001 4 4 | 0000000000000006 1 5 | 0000000000000004 1 6 | 0000000000000003 1 7 | 0000000000000002 1 8 | -------------------------------------------------------------------------------- /test/srcs/07-exception.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | double foo(int x) { 5 | if(x == 2) { 6 | throw "Exception"; 7 | } 8 | return 1*x; 9 | } 10 | 11 | int main(int argc, char* argv[]) { 12 | try { 13 | foo(argc); 14 | } catch(...) { 15 | printf("Caught an exception."); 16 | } 17 | return 0; 18 | } 19 | 20 | // RUN: clang -c -g -emit-llvm %s -o %t.1.bc 21 | // RUN: opt -instnamer %t.1.bc -o %t.bc 22 | // RUN: llvm-epp %t.bc -o %t.profile 2> %t.epp.log 23 | // RUN: clang -v %t.epp.bc -o %t-exec -lepp-rt -lstdc++ 2> %t.compile 24 | // RUN: %t-exec 2 > %t.log 25 | // RUN: llvm-epp -p=%t.profile %t.bc 2> %t.decode 26 | // RUN: diff -aub %t.profile %s.txt 27 | -------------------------------------------------------------------------------- /test/srcs/07-exception.cxx.txt: -------------------------------------------------------------------------------- 1 | 0 1 2 | 0000000000000000 1 3 | 4 1 4 | 0000000000000001 1 5 | -------------------------------------------------------------------------------- /test/srcs/08-pthread.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | void *foo(void *t) { 9 | for(int i = 0; i < 3; i++) { 10 | printf("This is a loop"); 11 | } 12 | return NULL; 13 | } 14 | 15 | 16 | int main(int argc, char* argv[]) { 17 | printf("main: %lu", syscall(__NR_gettid)); 18 | pthread_t thread; 19 | pthread_create(&thread, NULL, foo, NULL); 20 | pthread_join(thread, NULL); 21 | return 0; 22 | } 23 | 24 | // RUN: clang -c -g -emit-llvm %s -o %t.1.bc 25 | // RUN: opt -instnamer %t.1.bc -o %t.bc 26 | // RUN: llvm-epp %t.bc -o %t.profile 27 | // RUN: clang -v %t.epp.bc -o %t-exec -lepp-rt -lpthread 2> %t.compile 28 | // RUN: %t-exec > %t.log 29 | // RUN: llvm-epp -p=%t.profile %t.bc 2> %t.decode 30 | // RUN: diff -aub %t.profile %s.txt 31 | -------------------------------------------------------------------------------- /test/srcs/08-pthread.c.txt: -------------------------------------------------------------------------------- 1 | 0 5 2 | 0000000000000000 2 3 | 0000000000000004 1 4 | 0000000000000003 1 5 | 0000000000000002 1 6 | 0000000000000001 1 7 | 3 1 8 | 0000000000000000 1 9 | -------------------------------------------------------------------------------- /test/srcs/09-pthread2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | void *foo(void *t) { 9 | for(int i = 0; i < 3; i++) { 10 | printf("This is a loop"); 11 | } 12 | return NULL; 13 | } 14 | 15 | 16 | int main(int argc, char* argv[]) { 17 | printf("main: %lu", syscall(__NR_gettid)); 18 | pthread_t t1, t2; 19 | pthread_create(&t1, NULL, foo, NULL); 20 | pthread_create(&t2, NULL, foo, NULL); 21 | pthread_join(t1, NULL); 22 | pthread_join(t2, NULL); 23 | return 0; 24 | } 25 | 26 | // RUN: clang -c -g -emit-llvm %s -o %t.1.bc 27 | // RUN: opt -instnamer %t.1.bc -o %t.bc 28 | // RUN: llvm-epp %t.bc -o %t.profile 29 | // RUN: clang -v %t.epp.bc -o %t-exec -lepp-rt -lpthread 2> %t.compile 30 | // RUN: %t-exec > %t.log 31 | // RUN: llvm-epp -p=%t.profile %t.bc 2> %t.decode 32 | // RUN: diff -aub %t.profile %s.txt 33 | -------------------------------------------------------------------------------- /test/srcs/09-pthread2.c.txt: -------------------------------------------------------------------------------- 1 | 0 5 2 | 0000000000000000 4 3 | 0000000000000004 2 4 | 0000000000000003 2 5 | 0000000000000002 2 6 | 0000000000000001 2 7 | 3 1 8 | 0000000000000000 1 9 | -------------------------------------------------------------------------------- /test/srcs/10-omp.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * FILE: omp_hello.c 3 | * DESCRIPTION: 4 | * OpenMP Example - Hello World - C/C++ Version 5 | * In this simple example, the master thread forks a parallel region. 6 | * All threads in the team obtain their unique thread number and print it. 7 | * The master thread only prints the total number of threads. Two OpenMP 8 | * library routines are used to obtain the number of threads and each 9 | * thread's number. 10 | * AUTHOR: Blaise Barney 5/99 11 | * LAST REVISED: 04/06/05 12 | ******************************************************************************/ 13 | #include 14 | #include 15 | #include 16 | 17 | int main (int argc, char *argv[]) 18 | { 19 | int nthreads, tid; 20 | 21 | /* Fork a team of threads giving them their own copies of variables */ 22 | #pragma omp parallel private(nthreads, tid) 23 | { 24 | 25 | /* Obtain thread number */ 26 | tid = omp_get_thread_num(); 27 | printf("Hello World from thread = %d\n", tid); 28 | 29 | /* Only master thread does this */ 30 | if (tid == 0) 31 | { 32 | nthreads = omp_get_num_threads(); 33 | printf("Number of threads = %d\n", nthreads); 34 | } 35 | 36 | } /* All threads join master thread and disband */ 37 | 38 | } 39 | 40 | // RUN: clang -fopenmp -c -g -emit-llvm %s -o %t.1.bc 41 | // RUN: opt -instnamer %t.1.bc -o %t.bc 42 | // RUN: llvm-epp %t.bc -o %t.profile 43 | // RUN: clang -fopenmp -v %t.epp.bc -o %t-exec -lepp-rt -lpthread 2> %t.compile 44 | // RUN: OMP_NUM_THREADS=10 %t-exec > %t.log 45 | // RUN: llvm-epp -p=%t.profile %t.bc 2> %t.decode 46 | // RUN: diff -aub %t.profile %s.txt 47 | -------------------------------------------------------------------------------- /test/srcs/10-omp.c.txt: -------------------------------------------------------------------------------- 1 | 0 1 2 | 0000000000000000 1 3 | 2 2 4 | 0000000000000001 9 5 | 0000000000000000 1 6 | -------------------------------------------------------------------------------- /test/srcs/11-omp-for.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | int main() 7 | { 8 | double sinTable[256]; 9 | 10 | #pragma omp parallel for 11 | for(int n=0; n<256; ++n) 12 | sinTable[n] = sin(2 * M_PI * n / 256); 13 | 14 | // the table is now initialized 15 | } 16 | 17 | // RUN: clang -fopenmp -c -g -emit-llvm %s -o %t.1.bc 18 | // RUN: opt -instnamer %t.1.bc -o %t.bc 19 | // RUN: llvm-epp %t.bc -o %t.profile 20 | // RUN: clang -fopenmp -v %t.epp.bc -o %t-exec -lepp-rt -lpthread -lm 2> %t.compile 21 | // RUN: OMP_NUM_THREADS=4 %t-exec > %t.log 22 | // RUN: llvm-epp -p=%t.profile %t.bc 2> %t.decode 23 | // RUN: diff -aub %t.profile %s.txt 24 | -------------------------------------------------------------------------------- /test/srcs/11-omp-for.c.txt: -------------------------------------------------------------------------------- 1 | 0 1 2 | 0000000000000000 1 3 | 2 5 4 | 0000000000000002 252 5 | 0000000000000005 4 6 | 0000000000000004 4 7 | 0000000000000003 4 8 | 0000000000000001 4 9 | -------------------------------------------------------------------------------- /test/srcs/12-thread.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void foo() 6 | { 7 | // simulate expensive operation 8 | std::this_thread::sleep_for(std::chrono::seconds(1)); 9 | } 10 | 11 | void bar() 12 | { 13 | // simulate expensive operation 14 | std::this_thread::sleep_for(std::chrono::seconds(1)); 15 | } 16 | 17 | int main() 18 | { 19 | std::cout << "starting first helper...\n"; 20 | std::thread helper1(foo); 21 | 22 | std::cout << "starting second helper...\n"; 23 | std::thread helper2(bar); 24 | 25 | std::cout << "waiting for helpers to finish..." << std::endl; 26 | helper1.join(); 27 | helper2.join(); 28 | 29 | std::cout << "done!\n"; 30 | } 31 | 32 | // RUN: clang -std=c++11 -c -g -emit-llvm %s -o %t.1.bc 33 | // RUN: opt -instnamer %t.1.bc -o %t.bc 34 | // RUN: llvm-epp %t.bc -o %t.profile 35 | // RUN: clang -std=c++11 -v %t.epp.bc -o %t-exec -lepp-rt -lpthread -lstdc++ 2> %t.compile 36 | // RUN: %t-exec > %t.log 37 | // RUN: llvm-epp -p=%t.profile %t.bc 2> %t.decode 38 | // RUN: diff -aub <(head -n 30 %t.profile) <(head -n 30 %s.txt) 39 | -------------------------------------------------------------------------------- /test/srcs/12-thread.cxx.txt: -------------------------------------------------------------------------------- 1 | 0 1 2 | 0000000000000000 1 3 | 4 1 4 | 0000000000000000 1 5 | 5 1 6 | 0000000000000001 2 7 | 6 1 8 | 0000000000000000 2 9 | 7 1 10 | 0000000000000000 1 11 | 8 1 12 | 0000000000000000 1 13 | 11 1 14 | 0000000000000000 2 15 | 16 1 16 | 0000000000000001 2 17 | 17 1 18 | 0000000000000000 2 19 | 19 1 20 | 0000000000000000 2 21 | 21 1 22 | 0000000000000000 4 23 | 22 1 24 | 0000000000000000 2 25 | 26 1 26 | 0000000000000000 2 27 | 27 1 28 | 0000000000000000 2 29 | 28 1 30 | 0000000000000000 2 31 | 29 1 32 | 0000000000000000 2 33 | 30 1 34 | 0000000000000000 2 35 | 31 1 36 | 0000000000000000 14 37 | 32 1 38 | 0000000000000000 2 39 | 34 1 40 | 0000000000000000 2 41 | 35 1 42 | 0000000000000000 2 43 | 36 1 44 | 0000000000000000 6 45 | 37 1 46 | 0000000000000000 2 47 | 38 1 48 | 0000000000000000 2 49 | 39 1 50 | 0000000000000000 2 51 | 41 1 52 | 0000000000000000 2 53 | 42 1 54 | 0000000000000000 2 55 | 43 1 56 | 0000000000000000 4 57 | 44 1 58 | 0000000000000000 2 59 | 46 1 60 | 0000000000000000 4 61 | 47 1 62 | 0000000000000000 2 63 | 48 1 64 | 0000000000000000 2 65 | 49 1 66 | 0000000000000000 20 67 | 50 1 68 | 0000000000000000 2 69 | 51 1 70 | 0000000000000000 2 71 | 52 1 72 | 0000000000000000 8 73 | 53 1 74 | 0000000000000000 2 75 | 54 1 76 | 0000000000000000 2 77 | 55 1 78 | 0000000000000000 2 79 | 56 1 80 | 0000000000000000 2 81 | 57 1 82 | 0000000000000000 2 83 | 58 1 84 | 0000000000000000 4 85 | 59 1 86 | 0000000000000000 2 87 | 60 1 88 | 0000000000000000 2 89 | 61 1 90 | 0000000000000000 2 91 | 62 1 92 | 0000000000000000 6 93 | 63 1 94 | 0000000000000000 2 95 | 64 1 96 | 0000000000000000 2 97 | 65 2 98 | 0000000000000002 2 99 | 0000000000000000 2 100 | 66 1 101 | 0000000000000000 4 102 | 67 1 103 | 0000000000000000 4 104 | 68 1 105 | 0000000000000000 2 106 | 69 1 107 | 0000000000000000 4 108 | 70 1 109 | 0000000000000001 2 110 | 71 1 111 | 0000000000000000 2 112 | 74 1 113 | 0000000000000000 2 114 | 75 1 115 | 0000000000000000 6 116 | 76 1 117 | 0000000000000000 2 118 | 77 1 119 | 0000000000000000 2 120 | 78 1 121 | 0000000000000000 2 122 | 79 1 123 | 0000000000000000 6 124 | 80 1 125 | 0000000000000000 2 126 | 81 1 127 | 0000000000000000 2 128 | 83 1 129 | 0000000000000000 2 130 | 84 1 131 | 0000000000000000 2 132 | 85 1 133 | 0000000000000000 2 134 | 86 1 135 | 0000000000000000 2 136 | 91 1 137 | 0000000000000000 2 138 | 92 1 139 | 0000000000000000 2 140 | 93 1 141 | 0000000000000000 2 142 | 94 1 143 | 0000000000000000 2 144 | 95 1 145 | 0000000000000000 2 146 | 96 1 147 | 0000000000000000 2 148 | 98 1 149 | 0000000000000000 2 150 | 99 1 151 | 0000000000000000 2 152 | 100 1 153 | 0000000000000000 2 154 | 102 1 155 | 0000000000000000 2 156 | 103 1 157 | 0000000000000000 4 158 | 104 1 159 | 0000000000000000 2 160 | 105 1 161 | 0000000000000000 2 162 | 106 1 163 | 0000000000000000 14 164 | 107 1 165 | 0000000000000000 4 166 | 108 1 167 | 0000000000000000 4 168 | 109 1 169 | 0000000000000000 4 170 | 110 1 171 | 0000000000000000 2 172 | 111 1 173 | 0000000000000000 2 174 | 112 1 175 | 0000000000000000 2 176 | 113 1 177 | 0000000000000000 2 178 | 114 1 179 | 0000000000000000 6 180 | 115 1 181 | 0000000000000000 6 182 | 116 1 183 | 0000000000000000 2 184 | 117 1 185 | 0000000000000000 8 186 | 118 1 187 | 0000000000000000 2 188 | 119 1 189 | 0000000000000000 4 190 | 120 1 191 | 0000000000000000 2 192 | 121 1 193 | 0000000000000000 4 194 | 122 1 195 | 0000000000000000 2 196 | 124 1 197 | 0000000000000000 2 198 | 125 1 199 | 0000000000000000 2 200 | 126 1 201 | 0000000000000000 4 202 | 127 1 203 | 0000000000000000 2 204 | 128 1 205 | 0000000000000000 2 206 | 129 1 207 | 0000000000000000 2 208 | 130 1 209 | 0000000000000000 2 210 | 131 1 211 | 0000000000000000 2 212 | 132 1 213 | 0000000000000000 2 214 | 133 1 215 | 0000000000000000 2 216 | 134 1 217 | 0000000000000000 2 218 | 135 1 219 | 0000000000000000 4 220 | 136 1 221 | 0000000000000001 6 222 | 137 1 223 | 0000000000000003 3 224 | 138 1 225 | 0000000000000000 3 226 | 139 1 227 | 0000000000000000 3 228 | 140 1 229 | 0000000000000000 3 230 | 143 1 231 | 0000000000000000 2 232 | 144 1 233 | 0000000000000000 1 234 | -------------------------------------------------------------------------------- /test/srcs/13-switch.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | int main(int argc, char* argv[]) { 4 | for(int i = 0; i < 10; i++) { 5 | switch(i%3) { 6 | case 0: 7 | printf("case 0"); 8 | break; 9 | case 1: 10 | printf("case 1"); 11 | break; 12 | default: 13 | printf("case "); 14 | } 15 | } 16 | return 0; 17 | } 18 | 19 | // RUN: clang -c -g -emit-llvm %s -o %t.1.bc 20 | // RUN: opt -instnamer %t.1.bc -o %t.bc 21 | // RUN: llvm-epp %t.bc -o %t.profile 22 | // RUN: clang -v %t.epp.bc -o %t-exec -lepp-rt 2> %t.compile 23 | // RUN: %t-exec > %t.log 24 | // RUN: llvm-epp -p=%t.profile %t.bc 2> %t.decode 25 | // RUN: diff -aub %t.profile %s.txt 26 | -------------------------------------------------------------------------------- /test/srcs/13-switch.c.txt: -------------------------------------------------------------------------------- 1 | 0 7 2 | 0000000000000002 3 3 | 0000000000000001 3 4 | 0000000000000000 3 5 | 0000000000000007 1 6 | 0000000000000005 1 7 | 0000000000000004 1 8 | 0000000000000003 1 9 | -------------------------------------------------------------------------------- /test/srcs/14-triangle-loop.c: -------------------------------------------------------------------------------- 1 | 2 | int main(int argc, char* argv[]) { 3 | if(argc > 2) { 4 | for(int i = 0; i < 10; i++) { 5 | if(i%2) { 6 | printf("This is a loop"); 7 | } 8 | } 9 | } 10 | 11 | for(int i = 0; i < 10; i++) { 12 | if(i%3) { 13 | printf("This is another loop"); 14 | } 15 | } 16 | 17 | return 0; 18 | } 19 | 20 | // RUN: clang -c -g -emit-llvm %s -o %t.1.bc 21 | // RUN: opt -instnamer %t.1.bc -o %t.bc 22 | // RUN: llvm-epp %t.bc -o %t.profile 23 | // RUN: clang -v %t.epp.bc -o %t-exec -lepp-rt 2> %t.compile 24 | // RUN: %t-exec 1 2 3 > %t.log 25 | // RUN: llvm-epp -p=%t.profile %t.bc 2> %t.decode 26 | // RUN: diff -aub %t.profile %s.txt 27 | -------------------------------------------------------------------------------- /test/srcs/14-triangle-loop.c.txt: -------------------------------------------------------------------------------- 1 | 0 11 2 | 0000000000000002 6 3 | 0000000000000009 5 4 | 000000000000000a 4 5 | 0000000000000003 3 6 | 000000000000000e 1 7 | 000000000000000c 1 8 | 000000000000000b 1 9 | 0000000000000007 1 10 | 0000000000000005 1 11 | 0000000000000004 1 12 | 0000000000000000 1 13 | -------------------------------------------------------------------------------- /test/srcs/15-crit-ex.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // This tests for instrumentation along critical edges where 5 | // the destination of the edge is an exception handling pad block. 6 | 7 | int main(int argc, char* argv[]) { 8 | try { 9 | std::cout << "test"; 10 | std::cout << "test2"; 11 | } catch(...) { 12 | printf("Caught an exception."); 13 | } 14 | return 0; 15 | } 16 | 17 | // RUN: clang -c -g -emit-llvm %s -o %t.1.bc 18 | // RUN: opt -O2 -instnamer %t.1.bc -o %t.bc 19 | // RUN: llvm-epp %t.bc -o %t.profile 2> %t.epp.log 20 | // RUN: clang -v %t.epp.bc -o %t-exec -lepp-rt -lstdc++ 2> %t.compile 21 | // RUN: %t-exec > %t.log 22 | // RUN: llvm-epp -p=%t.profile %t.bc 2> %t.decode 23 | // RUN: diff -aub %t.profile %s.txt 24 | -------------------------------------------------------------------------------- /test/srcs/15-crit-ex.cxx.txt: -------------------------------------------------------------------------------- 1 | 0 1 2 | 0000000000000000 1 3 | 4 1 4 | 0000000000000000 1 5 | 11 1 6 | 0000000000000000 1 7 | -------------------------------------------------------------------------------- /test/srcs/16-unreach.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char* argv[]) { 5 | if(argc > 2) { 6 | exit(0); 7 | } 8 | else { 9 | printf("This is a diamond"); 10 | } 11 | return 0; 12 | } 13 | 14 | // RUN: clang -c -g -emit-llvm %s -o %t.1.bc 15 | // RUN: opt -instnamer %t.1.bc -o %t.bc 16 | // RUN: llvm-epp %t.bc -o %t.profile 17 | // RUN: clang -v %t.epp.bc -o %t-exec -lepp-rt 2> %t.compile 18 | // RUN: %t-exec 2 3 > %t.log 19 | // RUN: llvm-epp -p=%t.profile %t.bc 2> %t.decode 20 | // RUN: diff -aub %t.profile %s.txt 21 | -------------------------------------------------------------------------------- /test/srcs/16-unreach.c.txt: -------------------------------------------------------------------------------- 1 | 0 1 2 | 0000000000000000 1 3 | -------------------------------------------------------------------------------- /test/srcs/17-self-loop.c: -------------------------------------------------------------------------------- 1 | 2 | int main(int argc, char* argv[]) { 3 | loop: 4 | printf("loop\n"); 5 | goto loop; 6 | return 0; 7 | } 8 | 9 | // RUN: clang -O3 -c -g -emit-llvm %s -o %t.1.bc 10 | // RUN: opt -instnamer %t.1.bc -o %t.bc 11 | // RUN: llvm-epp %t.bc -o %t.profile 12 | // RUN: clang -v %t.epp.bc -o %t-exec -lepp-rt 2> %t.compile 13 | // RUN: timeout 0.01s %t-exec || true 14 | -------------------------------------------------------------------------------- /tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(llvm-epp) 2 | -------------------------------------------------------------------------------- /tools/llvm-epp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LLVM_USED_LIBS epp-inst) 2 | 3 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 4 | 5 | add_executable(llvm-epp 6 | main.cpp 7 | ) 8 | 9 | llvm_map_components_to_libnames(REQ_LLVM_LIBRARIES ${LLVM_TARGETS_TO_BUILD} 10 | asmparser core linker bitreader bitwriter irreader ipo scalaropts 11 | analysis target mc support) 12 | 13 | target_link_libraries(llvm-epp epp-inst ${REQ_LLVM_LIBRARIES}) 14 | 15 | # Platform dependencies. 16 | #target_link_libraries(epp 17 | #pthread 18 | #dl 19 | #curses 20 | #) 21 | 22 | set_target_properties(llvm-epp 23 | PROPERTIES 24 | LINKER_LANGUAGE CXX 25 | PREFIX "") 26 | 27 | install(TARGETS llvm-epp 28 | RUNTIME DESTINATION bin) 29 | 30 | -------------------------------------------------------------------------------- /tools/llvm-epp/main.cpp: -------------------------------------------------------------------------------- 1 | #define DEBUG_TYPE "epp_tool" 2 | #include "llvm/ADT/SmallString.h" 3 | #include "llvm/ADT/Triple.h" 4 | #include "llvm/Analysis/BasicAliasAnalysis.h" 5 | #include "llvm/Analysis/CallGraph.h" 6 | #include "llvm/Analysis/TargetLibraryInfo.h" 7 | #include "llvm/Analysis/TypeBasedAliasAnalysis.h" 8 | #include "llvm/AsmParser/Parser.h" 9 | #include "llvm/Bitcode/BitcodeReader.h" 10 | #include "llvm/Bitcode/BitcodeWriter.h" 11 | #include "llvm/CodeGen/LinkAllAsmWriterComponents.h" 12 | #include "llvm/CodeGen/LinkAllCodegenComponents.h" 13 | #include "llvm/IR/DataLayout.h" 14 | #include "llvm/IR/IRPrintingPasses.h" 15 | #include "llvm/IR/LLVMContext.h" 16 | #include "llvm/IR/LegacyPassManager.h" 17 | #include "llvm/IR/Module.h" 18 | #include "llvm/IR/Verifier.h" 19 | #include "llvm/IRReader/IRReader.h" 20 | #include "llvm/Linker/Linker.h" 21 | #include "llvm/MC/SubtargetFeature.h" 22 | #include "llvm/Pass.h" 23 | #include "llvm/Support/CommandLine.h" 24 | #include "llvm/Support/Debug.h" 25 | #include "llvm/Support/FileUtilities.h" 26 | #include "llvm/Support/FormattedStream.h" 27 | #include "llvm/Support/Host.h" 28 | #include "llvm/Support/ManagedStatic.h" 29 | #include "llvm/Support/Path.h" 30 | #include "llvm/Support/PrettyStackTrace.h" 31 | #include "llvm/Support/Program.h" 32 | #include "llvm/Support/Signals.h" 33 | #include "llvm/Support/SourceMgr.h" 34 | #include "llvm/Support/TargetRegistry.h" 35 | #include "llvm/Support/TargetSelect.h" 36 | #include "llvm/Support/ToolOutputFile.h" 37 | #include "llvm/Support/raw_ostream.h" 38 | #include "llvm/Target/TargetMachine.h" 39 | #include "llvm/Transforms/Scalar.h" 40 | 41 | #include "llvm/Analysis/LoopInfo.h" 42 | #include "llvm/Analysis/Passes.h" 43 | #include "llvm/IR/DebugInfo.h" 44 | 45 | #include 46 | #include 47 | 48 | #include "BreakSelfLoopsPass.h" 49 | #include "EPPPathPrinter.h" 50 | #include "EPPProfile.h" 51 | #include "SplitLandingPadPredsPass.h" 52 | 53 | using namespace std; 54 | using namespace llvm; 55 | using namespace llvm::sys; 56 | using namespace epp; 57 | 58 | cl::OptionCategory LLVMEppOptionCategory("EPP Options", 59 | "Additional options for the EPP tool"); 60 | 61 | cl::opt inPath(cl::Positional, cl::desc("Module to analyze"), 62 | cl::value_desc("filename"), cl::Required, 63 | cl::cat(LLVMEppOptionCategory)); 64 | 65 | cl::opt 66 | profileOutputFilename("o", cl::desc("Filename of the output path profile"), 67 | cl::value_desc("filename"), 68 | cl::cat(LLVMEppOptionCategory), 69 | cl::init("path-profile-results.txt")); 70 | 71 | cl::opt profile("p", cl::desc("Path to path profiling results"), 72 | cl::value_desc("filename"), 73 | cl::cat(LLVMEppOptionCategory)); 74 | 75 | cl::opt stripDebug( 76 | "s", cl::desc("Remove debug information from the instrumented bitcode"), 77 | cl::value_desc("toggle"), cl::Hidden, cl::init(true), 78 | cl::cat(LLVMEppOptionCategory)); 79 | 80 | cl::opt dumpGraphs("d", 81 | cl::desc("Dump dot graphs of the different stages."), 82 | cl::value_desc("toggle"), cl::Hidden, cl::init(false), 83 | cl::cat(LLVMEppOptionCategory)); 84 | 85 | // cl::opt wideCounter( 86 | // "w", 87 | // cl::desc("Use wide (128 bit) counters. Only available on 64 bit 88 | // systems"), 89 | // cl::value_desc("boolean"), cl::init(false), 90 | // cl::cat(LLVMEppOptionCategory)); 91 | 92 | namespace { 93 | 94 | void saveModule(Module &m, StringRef filename) { 95 | error_code EC; 96 | raw_fd_ostream out(filename.data(), EC, sys::fs::F_None); 97 | 98 | if (EC) { 99 | report_fatal_error("error saving llvm module to '" + filename + 100 | "': \n" + EC.message()); 101 | } 102 | WriteBitcodeToFile(&m, out); 103 | } 104 | 105 | void instrumentModule(Module &module) { 106 | 107 | // Build up all of the passes that we want to run on the module. 108 | legacy::PassManager pm; 109 | pm.add(createLoopSimplifyPass()); 110 | pm.add(new epp::BreakSelfLoopsPass()); 111 | pm.add(createBreakCriticalEdgesPass()); 112 | pm.add(new epp::SplitLandingPadPredsPass()); 113 | pm.add(new LoopInfoWrapperPass()); 114 | pm.add(new epp::EPPProfile()); 115 | pm.add(createVerifierPass()); 116 | pm.run(module); 117 | 118 | auto replaceExt = [](string &s, const string &newExt) { 119 | string::size_type i = s.rfind('.', s.length()); 120 | if (i != string::npos) { 121 | s.replace(i + 1, newExt.length(), newExt); 122 | } 123 | }; 124 | 125 | // This removes debug information from the module which has 126 | // been instrumented by EPPProfile. Rarely debug information 127 | // which got moved around caused a crash in clang when being 128 | // compiled to an executable (observed in 447.dealII). 129 | if (stripDebug) { 130 | StripDebugInfo(module); 131 | } 132 | 133 | replaceExt(inPath, "epp.bc"); 134 | saveModule(module, inPath); 135 | } 136 | 137 | void interpretResults(Module &module, std::string filename) { 138 | legacy::PassManager pm; 139 | pm.add(createLoopSimplifyPass()); 140 | pm.add(new epp::BreakSelfLoopsPass()); 141 | pm.add(createBreakCriticalEdgesPass()); 142 | pm.add(new epp::SplitLandingPadPredsPass()); 143 | pm.add(new LoopInfoWrapperPass()); 144 | pm.add(new epp::EPPDecode()); 145 | pm.add(new epp::EPPPathPrinter()); 146 | pm.add(createVerifierPass()); 147 | pm.run(module); 148 | } 149 | } 150 | 151 | int main(int argc, char **argv, const char **env) { 152 | // This boilerplate provides convenient stack traces and clean LLVM exit 153 | // handling. It also initializes the built in support for convenient 154 | // command line option handling. 155 | sys::PrintStackTraceOnErrorSignal(argv[0]); 156 | llvm::PrettyStackTraceProgram X(argc, argv); 157 | llvm_shutdown_obj shutdown; 158 | 159 | InitializeAllTargets(); 160 | InitializeAllTargetMCs(); 161 | InitializeAllAsmPrinters(); 162 | InitializeAllAsmParsers(); 163 | cl::AddExtraVersionPrinter( 164 | TargetRegistry::printRegisteredTargetsForVersion); 165 | cl::ParseCommandLineOptions(argc, argv); 166 | 167 | // Construct an IR file from the filename passed on the command line. 168 | SMDiagnostic err; 169 | LLVMContext context; 170 | unique_ptr module = parseIRFile(inPath.getValue(), err, context); 171 | 172 | if (!module.get()) { 173 | errs() << "Error reading bitcode file.\n"; 174 | err.print(argv[0], errs()); 175 | return -1; 176 | } 177 | 178 | if (!profile.empty()) { 179 | interpretResults(*module, profile.getValue()); 180 | } else { 181 | instrumentModule(*module); 182 | } 183 | 184 | return 0; 185 | } 186 | --------------------------------------------------------------------------------