├── .circleci └── config.yml ├── .clang-format ├── .gitignore ├── CMakeLists.txt ├── INSTALL.md ├── README.md ├── cmake ├── FindClang.cmake └── FindLLVM.cmake ├── docker └── Dockerfile ├── docs └── Doxyfile.in ├── include ├── DeadcodeElimination.h ├── FileManager.h ├── Frontend.h ├── GlobalReduction.h ├── IntegrationManager.h ├── LocalReduction.h ├── OptionManager.h ├── ProbabilisticModel.h ├── Profiler.h ├── Reduction.h ├── Reformat.h ├── Report.h ├── SourceManager.h ├── StatsManager.h ├── Transformation.h └── Visualization.h ├── lib └── wrappers │ ├── cc │ ├── clang │ ├── clang++ │ ├── cpp │ ├── g++ │ └── gcc ├── src ├── Chisel.cpp ├── core │ ├── DeadcodeElimination.cpp │ ├── Frontend.cpp │ ├── GlobalReduction.cpp │ ├── LocalReduction.cpp │ ├── ProbabilisticModel.cpp │ ├── Reduction.cpp │ ├── Reformat.cpp │ ├── SourceManager.cpp │ └── Transformation.cpp ├── utils │ ├── FileManager.cpp │ ├── IntegrationManager.cpp │ ├── OptionManager.cpp │ ├── Profiler.cpp │ ├── Report.cpp │ └── StatsManager.cpp └── xref │ └── Visualization.cpp └── test ├── CMakeLists.txt ├── basic0 ├── basic0.c ├── basic0.c.answer.c └── test.sh ├── basic1 ├── basic1.c ├── basic1.c.answer.c └── test.sh ├── basic2 ├── basic2.c ├── basic2.c.answer.c └── test.sh ├── basic3 ├── basic3.c ├── basic3.c.answer.c └── test.sh ├── basic4 ├── basic4.c ├── basic4.c.answer.c └── test.sh ├── basic5 ├── basic5.c ├── basic5.c.answer.c └── test.sh ├── conditional0 ├── conditional0.c ├── conditional0.c.answer.c └── test.sh ├── conditional1 ├── conditional1.c ├── conditional1.c.answer.c └── test.sh ├── conditional2 ├── conditional2.c ├── conditional2.c.answer.c └── test.sh ├── conditional3 ├── conditional3.c ├── conditional3.c.answer.c └── test.sh ├── dce0 ├── dce0.c ├── dce0.c.answer.c └── test.sh ├── dce1 ├── dce1.c ├── dce1.c.answer.c └── test.sh ├── dce2 ├── dce2.c ├── dce2.c.answer.c └── test.sh ├── dce3 ├── dce3.c ├── dce3.c.answer.c └── test.sh ├── dce4 ├── dce4.c ├── dce4.c.answer.c └── test.sh ├── do-while0 ├── do-while0.c ├── do-while0.c.answer.c └── test.sh ├── do-while1 ├── do-while1.c ├── do-while1.c.answer.c └── test.sh ├── do-while2 ├── do-while2.c ├── do-while2.c.answer.c └── test.sh ├── for0 ├── for0.c ├── for0.c.answer.c └── test.sh ├── for1 ├── for1.c ├── for1.c.answer.c └── test.sh ├── for2 ├── for2.c ├── for2.c.answer.c └── test.sh ├── for3 ├── for3.c ├── for3.c.answer.c └── test.sh ├── function0 ├── function0.c ├── function0.c.answer.c └── test.sh ├── function1 ├── function1.c ├── function1.c.answer.c └── test.sh ├── integration0 ├── header.h ├── integration0.c ├── integration0.c.answer.c ├── subfile0.c ├── subfile0.c.answer.c ├── subfile1.c ├── subfile1.c.answer.c └── test.sh ├── integration1 ├── Makefile ├── include │ └── header.h ├── integration1.c ├── integration1.c.answer.c ├── subfile0.c ├── subfile0.c.answer.c ├── subfile1.c ├── subfile1.c.answer.c └── test.sh ├── label0 ├── label0.c ├── label0.c.answer.c └── test.sh ├── loop0 ├── loop0.c ├── loop0.c.answer.c └── test.sh ├── loop1 ├── loop1.c ├── loop1.c.answer.c └── test.sh ├── macro0 ├── macro0.c ├── macro0.c.answer.c └── test.sh ├── macro1 ├── macro1.c ├── macro1.c.answer.c └── test.sh ├── switch0 ├── switch0.c ├── switch0.c.answer.c └── test.sh ├── switch1 ├── switch1.c ├── switch1.c.answer.c └── test.sh ├── switch2 ├── switch2.c ├── switch2.c.answer.c └── test.sh ├── switch3 ├── switch3.c ├── switch3.c.answer.c └── test.sh └── test.sh /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | jobs: 4 | build_debian: 5 | docker: 6 | - image: debian:buster 7 | steps: 8 | - checkout 9 | - run: apt-get update && apt-get install -y software-properties-common wget gnupg 10 | - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - 11 | - run: apt-add-repository "deb http://apt.llvm.org/buster/ llvm-toolchain-buster-8 main" && apt-get update 12 | - run: apt-get install -y clang-8 libclang-8-dev llvm-8-dev cmake git wget 13 | - run: apt-get install -y libspdlog-dev nlohmann-json-dev 14 | - run: apt-get install -y libmlpack-dev 15 | - run: ln -s /usr/bin/clang-8 /usr/bin/clang && ln -s /usr/bin/llvm-config-8 /usr/bin/llvm-config 16 | - run: mkdir build && cd build && cmake -DCMAKE_CXX_COMPILER=clang .. && make -j && make test 17 | build_ubuntu: 18 | docker: 19 | - image: ubuntu:18.04 20 | steps: 21 | - checkout 22 | - run: apt-get update && apt-get install -y software-properties-common wget 23 | - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - 24 | - run: apt-add-repository "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main" && apt-get update 25 | - run: apt-get install -y clang-8 libclang-8-dev llvm-8-dev cmake git wget 26 | - run: wget http://archive.ubuntu.com/ubuntu/pool/universe/s/spdlog/libspdlog-dev_1.3.1-1_amd64.deb 27 | - run: dpkg -i libspdlog-dev_1.3.1-1_amd64.deb 28 | - run: apt-get install -y nlohmann-json-dev 29 | - run: apt-get install -y libmlpack-dev 30 | - run: ln -s /usr/bin/clang-8 /usr/bin/clang && ln -s /usr/bin/llvm-config-8 /usr/bin/llvm-config 31 | - run: mkdir build && cd build && cmake -DCMAKE_CXX_COMPILER=clang .. && make -j && make test 32 | workflows: 33 | version: 2 34 | workflow: 35 | jobs: 36 | - build_debian 37 | - build_ubuntu 38 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Right 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: All 15 | AllowShortIfStatementsOnASingleLine: false 16 | AllowShortLoopsOnASingleLine: false 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: MultiLine 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BraceWrapping: 24 | AfterClass: false 25 | AfterControlStatement: false 26 | AfterEnum: false 27 | AfterFunction: false 28 | AfterNamespace: false 29 | AfterObjCDeclaration: false 30 | AfterStruct: false 31 | AfterUnion: false 32 | AfterExternBlock: false 33 | BeforeCatch: false 34 | BeforeElse: false 35 | IndentBraces: false 36 | SplitEmptyFunction: true 37 | SplitEmptyRecord: true 38 | SplitEmptyNamespace: true 39 | BreakBeforeBinaryOperators: None 40 | BreakBeforeBraces: Attach 41 | BreakBeforeInheritanceComma: false 42 | BreakInheritanceList: BeforeColon 43 | BreakBeforeTernaryOperators: true 44 | BreakConstructorInitializersBeforeComma: false 45 | BreakConstructorInitializers: BeforeColon 46 | BreakAfterJavaFieldAnnotations: false 47 | BreakStringLiterals: true 48 | ColumnLimit: 80 49 | CommentPragmas: '^ IWYU pragma:' 50 | CompactNamespaces: false 51 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 52 | ConstructorInitializerIndentWidth: 4 53 | ContinuationIndentWidth: 4 54 | Cpp11BracedListStyle: true 55 | DerivePointerAlignment: false 56 | DisableFormat: false 57 | ExperimentalAutoDetectBinPacking: false 58 | FixNamespaceComments: true 59 | ForEachMacros: 60 | - foreach 61 | - Q_FOREACH 62 | - BOOST_FOREACH 63 | IncludeBlocks: Preserve 64 | IncludeCategories: 65 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 66 | Priority: 2 67 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 68 | Priority: 3 69 | - Regex: '.*' 70 | Priority: 1 71 | IncludeIsMainRegex: '(Test)?$' 72 | IndentCaseLabels: false 73 | IndentPPDirectives: None 74 | IndentWidth: 2 75 | IndentWrappedFunctionNames: false 76 | JavaScriptQuotes: Leave 77 | JavaScriptWrapImports: true 78 | KeepEmptyLinesAtTheStartOfBlocks: true 79 | MacroBlockBegin: '' 80 | MacroBlockEnd: '' 81 | MaxEmptyLinesToKeep: 1 82 | NamespaceIndentation: None 83 | ObjCBinPackProtocolList: Auto 84 | ObjCBlockIndentWidth: 2 85 | ObjCSpaceAfterProperty: false 86 | ObjCSpaceBeforeProtocolList: true 87 | PenaltyBreakAssignment: 2 88 | PenaltyBreakBeforeFirstCallParameter: 19 89 | PenaltyBreakComment: 300 90 | PenaltyBreakFirstLessLess: 120 91 | PenaltyBreakString: 1000 92 | PenaltyBreakTemplateDeclaration: 10 93 | PenaltyExcessCharacter: 1000000 94 | PenaltyReturnTypeOnItsOwnLine: 60 95 | PointerAlignment: Right 96 | ReflowComments: true 97 | SortIncludes: false 98 | SortUsingDeclarations: true 99 | SpaceAfterCStyleCast: false 100 | SpaceAfterTemplateKeyword: true 101 | SpaceBeforeAssignmentOperators: true 102 | SpaceBeforeCpp11BracedList: false 103 | SpaceBeforeCtorInitializerColon: true 104 | SpaceBeforeInheritanceColon: true 105 | SpaceBeforeParens: ControlStatements 106 | SpaceBeforeRangeBasedForLoopColon: true 107 | SpaceInEmptyParentheses: false 108 | SpacesBeforeTrailingComments: 1 109 | SpacesInAngles: false 110 | SpacesInContainerLiterals: true 111 | SpacesInCStyleCastParentheses: false 112 | SpacesInParentheses: false 113 | SpacesInSquareBrackets: false 114 | Standard: Cpp11 115 | TabWidth: 8 116 | UseTab: Never 117 | ... 118 | 119 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.log 3 | *.out 4 | *.ast 5 | 6 | test/*/chisel-out/ 7 | test/*/*.origin.c 8 | test/*/*.chisel.c 9 | 10 | build/ 11 | *.csv 12 | 13 | # vim swap files 14 | .*.sw? 15 | .ycm_extra_conf.py 16 | 17 | # Mac OSX specific files 18 | .DS_store 19 | 20 | # vim plugin 21 | .ycm_extra_conf.py 22 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.9) 2 | project(chisel) 3 | 4 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 5 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 6 | 7 | file(MAKE_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) 8 | file(MAKE_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/wrappers) 9 | 10 | option(BUILD_STATIC "BUILTD_STATIC" OFF) 11 | 12 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") 13 | 14 | find_package(LLVM REQUIRED) 15 | find_package(Clang REQUIRED) 16 | 17 | set(CMAKE_CXX_FLAGS "${LLVM_COMPILE_FLAGS} ${CMAKE_CXX_FLAGS} -std=c++11 -lstdc++ -w -Os -march=native -fexceptions -pthread") 18 | if(CMAKE_BUILD_TYPE MATCHES Debug) 19 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=address") 20 | endif(CMAKE_BUILD_TYPE MATCHES Debug) 21 | 22 | message(STATUS "CXX flags: " ${CMAKE_CXX_FLAGS}) 23 | message(STATUS "LD flags: " ${CMAKE_EXE_LINKER_FLAGS}) 24 | 25 | include_directories(${LLVM_INCLUDE_DIRS}) 26 | include_directories(${CLANG_INCLUDE_DIRS}) 27 | include_directories(include) 28 | 29 | add_executable(chisel 30 | src/Chisel.cpp 31 | src/core/Frontend.cpp 32 | src/core/SourceManager.cpp 33 | src/core/Transformation.cpp 34 | src/core/Reduction.cpp 35 | src/core/GlobalReduction.cpp 36 | src/core/LocalReduction.cpp 37 | src/core/DeadcodeElimination.cpp 38 | src/core/Reformat.cpp 39 | src/core/ProbabilisticModel.cpp 40 | src/utils/FileManager.cpp 41 | src/utils/IntegrationManager.cpp 42 | src/utils/OptionManager.cpp 43 | src/utils/Report.cpp 44 | src/utils/Profiler.cpp 45 | src/utils/StatsManager.cpp 46 | src/xref/Visualization.cpp 47 | ) 48 | 49 | add_custom_target(lib ALL 50 | COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/lib/wrappers/* ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/wrappers/ 51 | ) 52 | 53 | target_link_libraries(chisel ${CLANG_LIBS} ${LLVM_LIBS_CORE} ${LLVM_LDFLAGS}) 54 | 55 | # for make test 56 | enable_testing() 57 | add_subdirectory(test) 58 | 59 | # for documents 60 | option(BUILD_DOCS "Build and Install Documents (Requires Doxygen)") 61 | if (BUILD_DOCS) 62 | find_package(Doxygen) 63 | if (DOXYGEN_FOUND) 64 | # set input and output files 65 | set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile.in) 66 | set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) 67 | 68 | # request to configure the file 69 | configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY) 70 | message("Doxygen build started") 71 | 72 | # note the option ALL which allows to build the docs together with the application 73 | add_custom_target(doc ALL 74 | COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT} 75 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 76 | COMMENT "Generating API documentation with Doxygen" 77 | VERBATIM ) 78 | else (DOXYGEN_FOUND) 79 | message("Doxygen need to be installed to generate the doxygen documentation") 80 | endif (DOXYGEN_FOUND) 81 | endif(BUILD_DOCS) 82 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # Installing Dependencies 2 | ## Requirements 3 | * CMake >= 3.11 4 | * Clang and LibClang >= 7.0 5 | * mlpack >= 2.0 6 | * spdlog >= 1.3.1 7 | 8 | You can install the requirements with the following commands. 9 | Make sure that your package manager installs the correct versions. 10 | ## Linux 11 | ```sh 12 | $ apt-get install clang libclang-dev llvm-dev cmake libspdlog-dev libmlpack-dev 13 | ``` 14 | ## macOS 15 | If you use [Homebrew](https://brew.sh): 16 | ```sh 17 | $ brew install llvm armadillo boost spdlog 18 | $ git clone https://github.com/mlpack/mlpack 19 | $ cd mlpack 20 | $ mkdir build && cd build 21 | $ cmake .. 22 | $ make 23 | $ make install 24 | ``` 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chisel [![CircleCI](https://circleci.com/gh/aspire-project/chisel.svg?style=svg)](https://circleci.com/gh/aspire-project/chisel) 2 | 3 | ## Installation 4 | ### Installing Dependencies 5 | See [INSTALL.md](INSTALL.md). 6 | 7 | ### Installing Chisel 8 | Once you have all the requirements, run the following commands: 9 | ```sh 10 | $ git clone https://github.com/aspire-project/chisel.git 11 | $ cd chisel 12 | $ mkdir build && cd build 13 | $ cmake .. 14 | $ make 15 | ``` 16 | Make sure to add Chisel to the PATH: 17 | ```sh 18 | $ export PATH=[chisel directory]/build/bin:$PATH 19 | ``` 20 | 21 | For ensuring that everything is working properly, run the following command: 22 | ```sh 23 | make test 24 | ``` 25 | 26 | ## Quick Start 27 | After building the project run the below command: 28 | ```sh 29 | $ chisel ./test.sh file.c 30 | ``` 31 | where `file.c` is a C program that you aim to reduce, and `test.sh` is 32 | the property testing script that returns `0` in a successful call. 33 | The reduced program is saved in `file.c.chisel.c` by default. 34 | -------------------------------------------------------------------------------- /cmake/FindClang.cmake: -------------------------------------------------------------------------------- 1 | if (NOT LLVM_INCLUDE_DIR OR NOT LLVM_LIB_DIR) 2 | message(FATAL_ERROR "No LLVM and Clang support requires LLVM") 3 | else (NOT LLVM_INCLUDE_DIR OR NOT LLVM_LIB_DIR) 4 | set(CLANG_INCLUDE_DIRS ${CLANG_INCLUDE_DIRS} ${LLVM_INCLUDE_DIR}) 5 | set(CLANG_INCLUDE_DIRS ${CLANG_INCLUDE_DIRS} ${CLANG_INCLUDE_DIR}) 6 | 7 | MACRO(FIND_AND_ADD_CLANG_LIB _libname_) 8 | find_library(CLANG_${_libname_}_LIB ${_libname_} ${LLVM_LIB_DIR} ${CLANG_LIB_DIR}) 9 | if (CLANG_${_libname_}_LIB) 10 | set(CLANG_LIBS ${CLANG_LIBS} ${CLANG_${_libname_}_LIB}) 11 | endif(CLANG_${_libname_}_LIB) 12 | ENDMACRO(FIND_AND_ADD_CLANG_LIB) 13 | 14 | FIND_AND_ADD_CLANG_LIB(clangFormat) 15 | FIND_AND_ADD_CLANG_LIB(clangFrontend) 16 | FIND_AND_ADD_CLANG_LIB(clangDriver) 17 | FIND_AND_ADD_CLANG_LIB(clangSema) 18 | FIND_AND_ADD_CLANG_LIB(clangChecker) 19 | FIND_AND_ADD_CLANG_LIB(clangAnalysis) 20 | FIND_AND_ADD_CLANG_LIB(clangRewrite) 21 | FIND_AND_ADD_CLANG_LIB(clangAST) 22 | FIND_AND_ADD_CLANG_LIB(clangParse) 23 | FIND_AND_ADD_CLANG_LIB(clangLex) 24 | FIND_AND_ADD_CLANG_LIB(clangBasic) 25 | FIND_AND_ADD_CLANG_LIB(clangARCMigrate) 26 | FIND_AND_ADD_CLANG_LIB(clangEdit) 27 | FIND_AND_ADD_CLANG_LIB(clangFrontendTool) 28 | FIND_AND_ADD_CLANG_LIB(clangSerialization) 29 | FIND_AND_ADD_CLANG_LIB(clangTooling) 30 | FIND_AND_ADD_CLANG_LIB(clangSema) 31 | FIND_AND_ADD_CLANG_LIB(clangRewriteCore) 32 | FIND_AND_ADD_CLANG_LIB(clangRewriteFrontend) 33 | FIND_AND_ADD_CLANG_LIB(clangASTMatchers) 34 | FIND_AND_ADD_CLANG_LIB(clangToolingCore) 35 | FIND_AND_ADD_CLANG_LIB(clangToolingInclusions) 36 | 37 | if(CLANG_LIBS) 38 | set(CLANG_FOUND TRUE) 39 | endif(CLANG_LIBS) 40 | 41 | MESSAGE(STATUS "Clang libs: " ${CLANG_LIBS}) 42 | 43 | if(CLANG_FOUND) 44 | message(STATUS "Found Clang") 45 | else(CLANG_FOUND) 46 | if(CLANG_FIND_REQUIRED) 47 | message(FATAL_ERROR "Could NOT find Clang") 48 | endif(CLANG_FIND_REQUIRED) 49 | endif(CLANG_FOUND) 50 | endif (NOT LLVM_INCLUDE_DIR OR NOT LLVM_LIB_DIR) 51 | -------------------------------------------------------------------------------- /cmake/FindLLVM.cmake: -------------------------------------------------------------------------------- 1 | # Detect LLVM and set various variable to link against the different component of LLVM 2 | # 3 | # NOTE: This is a modified version of the module originally found in the OpenGTL project 4 | # at www.opengtl.org 5 | # 6 | # LLVM_BIN_DIR : directory with LLVM binaries 7 | # LLVM_LIB_DIR : directory with LLVM library 8 | # LLVM_INCLUDE_DIR : directory with LLVM include 9 | # 10 | # LLVM_COMPILE_FLAGS : compile flags needed to build a program using LLVM headers 11 | # LLVM_LDFLAGS : ldflags needed to link 12 | # LLVM_LIBS_CORE : ldflags needed to link against a LLVM core library 13 | # LLVM_LIBS_JIT : ldflags needed to link against a LLVM JIT 14 | # LLVM_LIBS_JIT_OBJECTS : objects you need to add to your source when using LLVM JIT 15 | 16 | set(CONFIG_NAME "llvm-config") 17 | if (NOT "${LLVM_CONFIG_EXECUTABLE}" STREQUAL "") 18 | set(CONFIG_NAME "${LLVM_CONFIG_EXECUTABLE}") 19 | unset(LLVM_CONFIG_EXECUTABLE CACHE) 20 | endif() 21 | find_program(LLVM_CONFIG_EXECUTABLE NAMES "${CONFIG_NAME}" "${CONFIG_NAME}-8") 22 | 23 | if (BUILD_STATIC) 24 | set(LLVM_BUILD_OPT "--link-static") 25 | else (BUILD_STATIC) 26 | set(LLVM_BUILD_OPT "--link-shared") 27 | endif (BUILD_STATIC) 28 | 29 | exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --bindir OUTPUT_VARIABLE LLVM_BIN_DIR) 30 | exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --libdir OUTPUT_VARIABLE LLVM_LIB_DIR) 31 | exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --includedir OUTPUT_VARIABLE LLVM_INCLUDE_DIR) 32 | exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --cxxflags OUTPUT_VARIABLE LLVM_COMPILE_FLAGS) 33 | MESSAGE(STATUS "LLVM CXX flags: " ${LLVM_COMPILE_FLAGS}) 34 | execute_process(COMMAND ${LLVM_CONFIG_EXECUTABLE} --ldflags OUTPUT_VARIABLE LLVM_LDFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) 35 | execute_process(COMMAND ${LLVM_CONFIG_EXECUTABLE} --system-libs ${LLVM_BUILD_OPT} OUTPUT_VARIABLE LLVM_LDFLAGS2 OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) 36 | string(REPLACE "\n" " " LLVM_LDFLAGS "${LLVM_LDFLAGS} ${LLVM_LDFLAGS2}") 37 | string(STRIP ${LLVM_LDFLAGS} LLVM_LDFLAGS) 38 | MESSAGE(STATUS "LLVM LD flags: " ${LLVM_LDFLAGS}) 39 | exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --libs ${LLVM_BUILD_OPT} OUTPUT_VARIABLE LLVM_LIBS_CORE) 40 | MESSAGE(STATUS "LLVM core libs: " ${LLVM_LIBS_CORE}) 41 | 42 | if(LLVM_INCLUDE_DIR) 43 | set(LLVM_FOUND TRUE) 44 | endif(LLVM_INCLUDE_DIR) 45 | 46 | if(LLVM_FOUND) 47 | message(STATUS "Found LLVM") 48 | else(LLVM_FOUND) 49 | if(LLVM_FIND_REQUIRED) 50 | message(FATAL_ERROR "Could NOT find LLVM") 51 | endif(LLVM_FIND_REQUIRED) 52 | endif(LLVM_FOUND) 53 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:buster 2 | 3 | RUN apt-get update && apt-get install -y software-properties-common wget gnupg 4 | RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - 5 | RUN apt-add-repository "deb http://apt.llvm.org/buster/ llvm-toolchain-buster-8 main" && apt-get update 6 | RUN apt-get install -y clang-8 libclang-8-dev llvm-8-dev cmake git wget 7 | RUN apt-get install -y libspdlog-dev nlohmann-json-dev 8 | RUN apt-get install -y libmlpack-dev 9 | RUN ln -s /usr/bin/clang-8 /usr/bin/clang && ln -s /usr/bin/llvm-config-8 /usr/bin/llvm-config 10 | 11 | RUN git clone https://github.com/aspire-project/chisel 12 | RUN git clone https://github.com/aspire-project/chiselbench 13 | 14 | RUN mkdir -p chisel/build && cd chisel/build && CXX=clang cmake .. && make 15 | 16 | ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/chisel/build/bin 17 | ENV CC clang 18 | ENV CHISEL_BENCHMARK_HOME /chiselbench 19 | -------------------------------------------------------------------------------- /docs/Doxyfile.in: -------------------------------------------------------------------------------- 1 | DOXYFILE_ENCODING = UTF-8 2 | PROJECT_NAME = Chisel 3 | OUTPUT_LANGUAGE = English 4 | INPUT = @CMAKE_CURRENT_SOURCE_DIR@/src/ @CMAKE_CURRENT_SOURCE_DIR@/include 5 | OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@/doc/ 6 | FULL_PATH_NAMES = NO 7 | FILE_PATTERNS = *.cpp *.h 8 | UML_LOOK = YES 9 | RECURSIVE = YES 10 | STRIP_FROM_PATH = @CMAKE_CURRENT_SOURCE_DIR@/.. 11 | GENERATE_LATEX = NO 12 | FULL_PATH_NAMES = NO 13 | EXTRACT_ALL = YES 14 | -------------------------------------------------------------------------------- /include/DeadcodeElimination.h: -------------------------------------------------------------------------------- 1 | #ifndef DEADCODE_ELIMINATION_H 2 | #define DEADCODE_ELIMINATION_H 3 | 4 | #include 5 | #include 6 | 7 | #include "clang/AST/RecursiveASTVisitor.h" 8 | 9 | #include "Reduction.h" 10 | 11 | class DeadcodeElementCollectionVisitor; 12 | 13 | /// \brief Represents a sound dead-code elimination phase 14 | /// 15 | /// DeadcodeElimination removes unused statements without calling the oracle, 16 | /// and removes unused labels and unused variable declarations that are side-effect free. 17 | class DeadCodeElimination { 18 | public: 19 | static void Run(); 20 | }; 21 | 22 | class ClangDeadcodeElimination : public Transformation { 23 | friend class LocalElementCollectionVisitor; 24 | 25 | public: 26 | ClangDeadcodeElimination() : CollectionVisitor(NULL) {} 27 | ~ClangDeadcodeElimination() { delete CollectionVisitor; } 28 | 29 | void removeUnusedElements(); 30 | std::map LocationMapping; 31 | std::vector UnusedLocations; 32 | 33 | private: 34 | void Initialize(clang::ASTContext &Ctx); 35 | bool HandleTopLevelDecl(clang::DeclGroupRef D); 36 | clang::SourceRange getRemoveRange(clang::SourceLocation Loc); 37 | bool isConstant(clang::Stmt *S); 38 | 39 | DeadcodeElementCollectionVisitor *CollectionVisitor; 40 | }; 41 | 42 | class DeadcodeElementCollectionVisitor 43 | : public clang::RecursiveASTVisitor { 44 | public: 45 | DeadcodeElementCollectionVisitor(ClangDeadcodeElimination *R) : Consumer(R) {} 46 | 47 | bool VisitVarDecl(clang::VarDecl *VD); 48 | bool VisitLabelStmt(clang::LabelStmt *LS); 49 | 50 | private: 51 | ClangDeadcodeElimination *Consumer; 52 | }; 53 | 54 | class DCEFrontend { 55 | public: 56 | static bool Parse(std::string &Filename, ClangDeadcodeElimination *R); 57 | }; 58 | 59 | class BlockEliminationVisitor; 60 | 61 | class BlockElimination : public Transformation { 62 | friend class BlockEliminationVisitor; 63 | 64 | public: 65 | BlockElimination() : Visitor(NULL) {} 66 | ~BlockElimination() { delete Visitor; } 67 | 68 | void removeBlock(clang::CompoundStmt *CS); 69 | 70 | private: 71 | void Initialize(clang::ASTContext &Ctx); 72 | bool HandleTopLevelDecl(clang::DeclGroupRef D); 73 | void HandleTranslationUnit(clang::ASTContext &Ctx); 74 | 75 | std::set FunctionBodies; 76 | 77 | BlockEliminationVisitor *Visitor; 78 | }; 79 | 80 | class BlockEliminationVisitor 81 | : public clang::RecursiveASTVisitor { 82 | public: 83 | BlockEliminationVisitor(BlockElimination *R) : Consumer(R) {} 84 | 85 | bool VisitFunctionDecl(clang::FunctionDecl *FD); 86 | bool VisitCompoundStmt(clang::CompoundStmt *CS); 87 | 88 | private: 89 | BlockElimination *Consumer; 90 | }; 91 | 92 | #endif // DEADCODE_ELIMINATION_H 93 | -------------------------------------------------------------------------------- /include/FileManager.h: -------------------------------------------------------------------------------- 1 | #ifndef FILE_MANAGER_H 2 | #define FILE_MANAGER_H 3 | 4 | #include 5 | #include 6 | 7 | /// \brief Wrapper for low-level file manipulations 8 | class FileManager { 9 | public: 10 | static void Initialize(); 11 | static void Finalize(); 12 | static FileManager *GetInstance(); 13 | static std::string Readlink(std::string &Name); 14 | static std::string Dirname(std::string &Name); 15 | static std::string Basename(std::string &Name); 16 | 17 | std::string getTempFileName(std::string Suffix); 18 | void saveTemp(std::string Phase, bool Status); 19 | 20 | private: 21 | FileManager() {} 22 | ~FileManager() {} 23 | 24 | static FileManager *Instance; 25 | 26 | int TempCounter = 0; 27 | }; 28 | 29 | #endif // FILE_MANAGER_H 30 | -------------------------------------------------------------------------------- /include/Frontend.h: -------------------------------------------------------------------------------- 1 | #ifndef FRONTEND_H 2 | #define FRONTEND_H 3 | 4 | #include "clang/Parse/ParseAST.h" 5 | 6 | #include 7 | 8 | /// \brief Provides an independent frontend for any action on AST 9 | class Frontend { 10 | public: 11 | static bool Parse(std::string &FileName, clang::ASTConsumer *C); 12 | }; 13 | 14 | #endif // FRONTEND_H 15 | -------------------------------------------------------------------------------- /include/GlobalReduction.h: -------------------------------------------------------------------------------- 1 | #ifndef GLOBAL_REDUCTION_H 2 | #define GLOBAL_REDUCTION_H 3 | 4 | #include 5 | 6 | #include "clang/AST/RecursiveASTVisitor.h" 7 | 8 | #include "Reduction.h" 9 | 10 | class GlobalElementCollectionVisitor; 11 | 12 | /// \brief Represents a global reduction phase 13 | /// 14 | /// In global reduction phase, global declarations are reduced. 15 | class GlobalReduction : public Reduction { 16 | friend class GlobalElementCollectionVisitor; 17 | 18 | public: 19 | GlobalReduction() : CollectionVisitor(NULL) {} 20 | ~GlobalReduction() { delete CollectionVisitor; } 21 | 22 | private: 23 | void Initialize(clang::ASTContext &Ctx); 24 | bool HandleTopLevelDecl(clang::DeclGroupRef D); 25 | void HandleTranslationUnit(clang::ASTContext &Ctx); 26 | 27 | static DDElement CastElement(clang::Decl *D); 28 | 29 | bool callOracle(); 30 | bool test(DDElementVector &ToBeRemoved); 31 | bool isInvalidChunk(DDElementVector &Chunk); 32 | void filterElements(DDElementVector &Vec); 33 | 34 | std::vector Decls; 35 | std::map UseInfo; 36 | GlobalElementCollectionVisitor *CollectionVisitor; 37 | }; 38 | 39 | class GlobalElementCollectionVisitor 40 | : public clang::RecursiveASTVisitor { 41 | public: 42 | GlobalElementCollectionVisitor(GlobalReduction *R) : Consumer(R) {} 43 | 44 | bool VisitDeclRefExpr(clang::DeclRefExpr *DRE); 45 | bool VisitFunctionDecl(clang::FunctionDecl *FD); 46 | bool VisitVarDecl(clang::VarDecl *VD); 47 | bool VisitEmptyDecl(clang::EmptyDecl *ED); 48 | 49 | private: 50 | GlobalReduction *Consumer; 51 | }; 52 | 53 | #endif // GLOBAL_REDUCTION_H 54 | -------------------------------------------------------------------------------- /include/IntegrationManager.h: -------------------------------------------------------------------------------- 1 | #ifndef INTEGRATION_MANAGER_H 2 | #define INTEGRATION_MANAGER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /// \brief Manages build system integration 9 | class IntegrationManager { 10 | public: 11 | static void Initialize(); 12 | static void Finalize(); 13 | static IntegrationManager *GetInstance() { return Instance; } 14 | 15 | void capture(); 16 | std::vector &getOriginFilePaths() { return Origins; } 17 | std::vector getCC1Args(std::string &FileName); 18 | 19 | std::map> CompilationDB; 20 | 21 | private: 22 | static IntegrationManager *Instance; 23 | std::vector Origins; 24 | std::string WrapperDir; 25 | 26 | void buildCompilationDB(); 27 | 28 | std::string CaptureFilePath; 29 | }; 30 | 31 | #endif // INTEGRATION_MANAGER_H 32 | -------------------------------------------------------------------------------- /include/LocalReduction.h: -------------------------------------------------------------------------------- 1 | #ifndef LOCAL_REDUCTION_H 2 | #define LOCAL_REDUCTION_H 3 | 4 | #include 5 | #include 6 | 7 | #include "clang/AST/RecursiveASTVisitor.h" 8 | 9 | #include "Reduction.h" 10 | 11 | class LocalElementCollectionVisitor; 12 | 13 | /// \brief Represents a local reduction phase 14 | /// 15 | /// In local reduction phase, local statements are reduced 16 | /// hierarchically with respect to AST. 17 | class LocalReduction : public Reduction { 18 | friend class LocalElementCollectionVisitor; 19 | 20 | public: 21 | LocalReduction() : CollectionVisitor(NULL) {} 22 | ~LocalReduction() { delete CollectionVisitor; } 23 | 24 | private: 25 | void Initialize(clang::ASTContext &Ctx); 26 | bool HandleTopLevelDecl(clang::DeclGroupRef D); 27 | void HandleTranslationUnit(clang::ASTContext &Ctx); 28 | 29 | std::set toSet(std::vector &Vec); 30 | std::set setDifference(std::set &A, 31 | std::set &B); 32 | static DDElement CastElement(clang::Stmt *S); 33 | 34 | bool callOracle(); 35 | bool test(DDElementVector &ToBeRemoved); 36 | bool isInvalidChunk(DDElementVector &Chunk); 37 | void filterElements(std::vector &Vec); 38 | 39 | void doHierarchicalDeltaDebugging(clang::Stmt *S); 40 | void reduceSwitch(clang::SwitchStmt *SS); 41 | void reduceIf(clang::IfStmt *IS); 42 | void reduceWhile(clang::WhileStmt *WS); 43 | void reduceDoWhile(clang::DoStmt *DS); 44 | void reduceFor(clang::ForStmt *FS); 45 | void reduceCompound(clang::CompoundStmt *CS); 46 | void reduceLabel(clang::LabelStmt *LS); 47 | int countReturnStmts(std::set &Elements); 48 | bool noReturn(std::set &FunctionStmts, 49 | std::set &AllRemovedStmts); 50 | bool danglingLabel(std::set &Remaining); 51 | bool brokenDependency(std::set &Remaining); 52 | 53 | std::vector getDeclRefExprs(clang::Expr *E); 54 | std::vector getBodyStatements(clang::CompoundStmt *CS); 55 | 56 | void addDefUse(clang::DeclRefExpr *DRE, std::set &DU); 57 | 58 | std::set RemovedElements; 59 | std::vector Functions; 60 | std::queue Queue; 61 | 62 | LocalElementCollectionVisitor *CollectionVisitor; 63 | clang::FunctionDecl *CurrentFunction; 64 | }; 65 | 66 | class LocalElementCollectionVisitor 67 | : public clang::RecursiveASTVisitor { 68 | public: 69 | LocalElementCollectionVisitor(LocalReduction *R) : Consumer(R) {} 70 | 71 | bool VisitFunctionDecl(clang::FunctionDecl *FD); 72 | 73 | private: 74 | LocalReduction *Consumer; 75 | }; 76 | 77 | #endif // LOCAL_REDUCTION_H 78 | -------------------------------------------------------------------------------- /include/OptionManager.h: -------------------------------------------------------------------------------- 1 | #ifndef OPTION_MANAGER_H 2 | #define OPTION_MANAGER_H 3 | 4 | #include 5 | #include 6 | 7 | /// \brief Manages and processes all the command-line options that are passed to 8 | /// Chisel 9 | class OptionManager { 10 | public: 11 | static std::string BinFile; 12 | static std::vector InputFiles; 13 | static std::vector BuildCmd; 14 | static std::string InputFile; 15 | static std::string OracleFile; 16 | static std::string OutputDir; 17 | static bool Build; 18 | static bool SaveTemp; 19 | static bool SkipLearning; 20 | static bool SkipDelayLearning; 21 | static bool SkipGlobal; 22 | static bool SkipLocal; 23 | static bool NoCache; 24 | static bool SkipGlobalDep; 25 | static bool SkipLocalDep; 26 | static bool SkipDCE; 27 | static bool Profile; 28 | static bool Debug; 29 | static bool Stat; 30 | static bool XRef; 31 | 32 | static void showUsage(); 33 | static void handleOptions(int argc, char *argv[]); 34 | }; 35 | 36 | #endif // OPTION_MANAGER_H 37 | -------------------------------------------------------------------------------- /include/ProbabilisticModel.h: -------------------------------------------------------------------------------- 1 | #ifndef PROBABILISTIC_MODEL_H_ 2 | #define PROBABILISTIC_MODEL_H_ 3 | 4 | #include 5 | 6 | #include "clang/AST/ASTContext.h" 7 | 8 | #include 9 | #include 10 | 11 | using DDElement = llvm::PointerUnion; 12 | using DDElementVector = std::vector; 13 | 14 | /// \brief Represents the probabilistic model that is utilized in the reduction phase 15 | class ProbabilisticModel { 16 | public: 17 | ProbabilisticModel() : MyDecisionTree(2) {} 18 | void initialize(DDElementVector &Source); 19 | void clear(); 20 | void train(int Iteration); 21 | void addForTraining(DDElementVector &Source, DDElementVector &Chunk, 22 | bool Label); 23 | arma::uvec sortCandidates(DDElementVector &Source, 24 | std::vector &Chunks); 25 | 26 | private: 27 | arma::mat TrainingSet; 28 | arma::Row TrainingLabels; 29 | mlpack::tree::DecisionTree<> MyDecisionTree; 30 | 31 | arma::mat createFeatureVector(DDElementVector &Source, 32 | DDElementVector &Chunk); 33 | void printVector(arma::mat FeatureVector, bool Label); 34 | }; 35 | 36 | #endif // PROBABILISTIC_MODEL_H_ 37 | -------------------------------------------------------------------------------- /include/Profiler.h: -------------------------------------------------------------------------------- 1 | #ifndef PROFILER_H 2 | #define PROFILER_H 3 | 4 | #include "llvm/Support/Timer.h" 5 | 6 | /// \brief Keeps track of performance information that is used in preparing the report 7 | class Profiler { 8 | public: 9 | static void Initialize(); 10 | static Profiler *GetInstance(); 11 | static void Finalize(); 12 | 13 | void incrementGlobalReductionCounter(); 14 | void incrementSuccessfulGlobalReductionCounter(); 15 | void incrementLocalReductionCounter(); 16 | void incrementSuccessfulLocalReductionCounter(); 17 | 18 | int getGlobalReductionCounter() { return GlobalReductionCounter; } 19 | int getSuccessfulGlobalReductionCounter() { 20 | return SuccessfulGlobalReductionCounter; 21 | } 22 | int getLocalReductionCounter() { return LocalReductionCounter; } 23 | int getSuccessfulLocalReductionCounter() { 24 | return SuccessfulLocalReductionCounter; 25 | } 26 | 27 | llvm::Timer &getChiselTimer() { return ChiselTimer; } 28 | llvm::Timer &getLearningTimer() { return LearningTimer; } 29 | llvm::Timer &getOracleTimer() { return OracleTimer; } 30 | 31 | llvm::TimeRecord &getChiselTimeRecord() { return ChiselTimeRecord; } 32 | llvm::TimeRecord &getLearningTimeRecord() { return LearningTimeRecord; } 33 | llvm::TimeRecord &getOracleTimeRecord() { return OracleTimeRecord; } 34 | 35 | void beginChisel(); 36 | void endChisel(); 37 | 38 | void beginOracle(); 39 | void endOracle(); 40 | 41 | void beginLearning(); 42 | void endLearning(); 43 | 44 | private: 45 | Profiler() {} 46 | ~Profiler() {} 47 | 48 | static Profiler *Instance; 49 | 50 | int GlobalReductionCounter = 0; 51 | int SuccessfulGlobalReductionCounter = 0; 52 | int LocalReductionCounter = 0; 53 | int SuccessfulLocalReductionCounter = 0; 54 | 55 | llvm::TimeRecord ChiselTimeRecord; 56 | llvm::TimeRecord LearningTimeRecord; 57 | llvm::TimeRecord OracleTimeRecord; 58 | 59 | llvm::Timer ChiselTimer; 60 | llvm::Timer LearningTimer; 61 | llvm::Timer OracleTimer; 62 | }; 63 | 64 | #endif // PROFILER_H 65 | -------------------------------------------------------------------------------- /include/Reduction.h: -------------------------------------------------------------------------------- 1 | #ifndef REDUCTION_H 2 | #define REDUCTION_H 3 | 4 | #include 5 | 6 | #include "ProbabilisticModel.h" 7 | #include "Transformation.h" 8 | 9 | using DDElement = llvm::PointerUnion; 10 | using DDElementVector = std::vector; 11 | using DDElementSet = std::set; 12 | 13 | /// \brief Represents a general reduction step 14 | class Reduction : public Transformation { 15 | public: 16 | Reduction() {} 17 | ~Reduction() {} 18 | 19 | protected: 20 | virtual void Initialize(clang::ASTContext &Ctx); 21 | 22 | DDElementSet doDeltaDebugging(std::vector &Decls); 23 | 24 | virtual bool test(DDElementVector &ToBeRemoved) = 0; 25 | virtual bool callOracle(); 26 | virtual bool isInvalidChunk(DDElementVector &Chunk) = 0; 27 | 28 | DDElementSet toSet(DDElementVector &Vec); 29 | DDElementSet setDifference(DDElementSet &A, DDElementSet &B); 30 | 31 | private: 32 | ProbabilisticModel TheModel; 33 | std::set Cache; 34 | DDElementVector toVector(DDElementSet &Set); 35 | 36 | std::vector getCandidates(DDElementVector &Decls, 37 | int ChunkSize); 38 | }; 39 | 40 | #endif // REDUCTION_H 41 | -------------------------------------------------------------------------------- /include/Reformat.h: -------------------------------------------------------------------------------- 1 | #ifndef REFORMAT_H 2 | #define REFORMAT_H 3 | 4 | #include "clang/AST/RecursiveASTVisitor.h" 5 | #include "clang/Format/Format.h" 6 | 7 | #include "Transformation.h" 8 | 9 | /// \brief Represents a reformatting action 10 | class Reformat : public Transformation { 11 | public: 12 | Reformat() {} 13 | ~Reformat() {} 14 | 15 | private: 16 | void Initialize(clang::ASTContext &Ctx); 17 | void HandleTranslationUnit(clang::ASTContext &Ctx); 18 | void doReformatting(std::string FileName, clang::format::FormatStyle FS); 19 | std::vector createRanges(llvm::MemoryBuffer *Code); 20 | }; 21 | 22 | #endif // REFORMAT_H 23 | -------------------------------------------------------------------------------- /include/Report.h: -------------------------------------------------------------------------------- 1 | #ifndef REPORT_H 2 | #define REPORT_H 3 | 4 | /// \brief Prepares and pretty-prints the final report to the terminal 5 | class Report { 6 | public: 7 | static void print(); 8 | }; 9 | 10 | #endif // REPORT_H 11 | -------------------------------------------------------------------------------- /include/SourceManager.h: -------------------------------------------------------------------------------- 1 | #ifndef SOURCE_MANAGER_H 2 | #define SOURCE_MANAGER_H 3 | 4 | #include "clang/AST/ASTContext.h" 5 | #include "clang/AST/Expr.h" 6 | #include "clang/Basic/SourceManager.h" 7 | 8 | class SourceManager { 9 | public: 10 | static bool IsInHeader(const clang::SourceManager &SM, clang::Decl *D); 11 | static int GetStartingColumn(clang::SourceManager &SM, int Line); 12 | static clang::SourceLocation 13 | FindLocationAfterCond(const clang::SourceManager &SM, clang::Expr *E); 14 | static clang::SourceLocation GetRealLocation(clang::ASTContext *Context, 15 | clang::SourceLocation Loc); 16 | static clang::SourceLocation GetEndOfCond(const clang::SourceManager &SM, 17 | clang::Expr *E); 18 | static clang::SourceLocation GetBeginOfStmt(clang::ASTContext *Context, 19 | clang::Stmt *S); 20 | static clang::SourceLocation GetEndOfStmt(clang::ASTContext *Context, 21 | clang::Stmt *S); 22 | static clang::SourceLocation GetEndLocation(clang::ASTContext *Context, 23 | clang::SourceLocation Loc); 24 | static clang::SourceLocation 25 | GetEndLocationAfter(const clang::SourceManager &SM, clang::SourceRange Range, 26 | char Symbol); 27 | static clang::SourceLocation 28 | GetEndLocationUntil(const clang::SourceManager &SM, 29 | clang::SourceLocation EndLoc, 30 | clang::tok::TokenKind Symbol); 31 | static clang::SourceLocation 32 | GetEndLocationFromBegin(const clang::SourceManager &SM, 33 | clang::SourceRange Range); 34 | static llvm::StringRef GetSourceText(const clang::SourceManager &SM, 35 | const clang::SourceLocation &B, 36 | const clang::SourceLocation &E); 37 | static llvm::StringRef GetSourceText(const clang::SourceManager &SM, 38 | const clang::SourceRange &SR); 39 | }; 40 | #endif // SOURCE_MANAGER_H 41 | -------------------------------------------------------------------------------- /include/StatsManager.h: -------------------------------------------------------------------------------- 1 | #ifndef STATS_MANAGER_H 2 | #define STATS_MANAGER_H 3 | 4 | #include 5 | #include 6 | 7 | #include "clang/AST/ASTConsumer.h" 8 | #include "clang/AST/RecursiveASTVisitor.h" 9 | #include "clang/AST/Stmt.h" 10 | 11 | /// \brief Responsible for computing statistical information for a file 12 | class StatsManager { 13 | public: 14 | static void ComputeStats(std::string &FileName); 15 | static void ComputeStats(std::vector &FileNames); 16 | static void Print(); 17 | 18 | static int GetNumOfWords() { return NumOfWords; } 19 | static int GetNumOfStatements() { return NumOfStatements; } 20 | static int GetNumOfFunctions() { return NumOfFunctions; } 21 | 22 | static void IncreaseNumOfFunctions(); 23 | static void IncreaseNumOfStatements(); 24 | 25 | static bool isCountableStatement(clang::Stmt *S); 26 | 27 | private: 28 | StatsManager() {} 29 | StatsManager(std::string &FileName); 30 | ~StatsManager() {} 31 | 32 | static int NumOfWords; 33 | static int NumOfStatements; 34 | static int NumOfFunctions; 35 | }; 36 | 37 | class StatsVisitor; 38 | 39 | class StatsComputer : public clang::ASTConsumer { 40 | friend class StatsVisitor; 41 | 42 | public: 43 | StatsComputer() : Visitor(NULL) {} 44 | ~StatsComputer() { delete Visitor; } 45 | 46 | private: 47 | void Initialize(clang::ASTContext &Ctx); 48 | bool HandleTopLevelDecl(clang::DeclGroupRef D); 49 | 50 | StatsManager *Manager; 51 | StatsVisitor *Visitor; 52 | }; 53 | 54 | class StatsVisitor : public clang::RecursiveASTVisitor { 55 | public: 56 | StatsVisitor() {} 57 | 58 | bool VisitFunctionDecl(clang::FunctionDecl *FD); 59 | bool VisitStmt(clang::Stmt *S); 60 | }; 61 | 62 | #endif // STATS_MANAGER_H 63 | -------------------------------------------------------------------------------- /include/Transformation.h: -------------------------------------------------------------------------------- 1 | #ifndef TRANSFORMATION_H 2 | #define TRANSFORMATION_H 3 | 4 | #include "clang/AST/ASTConsumer.h" 5 | #include "clang/AST/ASTContext.h" 6 | #include "clang/AST/Expr.h" 7 | #include "clang/Rewrite/Core/Rewriter.h" 8 | 9 | /// \brief Represesnts a transformation action on an AST 10 | class Transformation : public clang::ASTConsumer { 11 | public: 12 | Transformation() {} 13 | ~Transformation() {} 14 | 15 | protected: 16 | virtual void Initialize(clang::ASTContext &Ctx); 17 | 18 | std::vector getAllChildren(clang::Stmt *S); 19 | bool callOracle(); 20 | void revertRemoval(const std::vector &Ranges, 21 | const std::vector &Reverts); 22 | void removeSourceText(const clang::SourceLocation &B, 23 | const clang::SourceLocation &E); 24 | 25 | clang::ASTContext *Context; 26 | clang::Rewriter TheRewriter; 27 | }; 28 | 29 | #endif // TRANSFORMATION_H 30 | -------------------------------------------------------------------------------- /include/Visualization.h: -------------------------------------------------------------------------------- 1 | #include "clang/AST/ASTContext.h" 2 | #include "clang/Frontend/FrontendActions.h" 3 | #include "clang/Tooling/JSONCompilationDatabase.h" 4 | #include "clang/Tooling/Tooling.h" 5 | #include "llvm/Support/CommandLine.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | class Visualization { 14 | public: 15 | void generate(std::string Filename); 16 | 17 | private: 18 | std::string getStdoutFromCommand(std::string Command); 19 | std::vector ParseNumbers(std::string String); 20 | void Save(std::vector Numbers, std::string Filename); 21 | }; 22 | -------------------------------------------------------------------------------- /lib/wrappers/cc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=$(basename $0) 4 | HOST_COMPILER=$(PATH=$CHISEL_OLD_PATH which $NAME) 5 | OUTPUT=$CHISEL_OUTPUT_DIR/"capture.txt" 6 | 7 | printf "%s" $NAME >>$OUTPUT 8 | for arg in "$@"; do 9 | if [[ $arg == *.c || $arg == *.cpp ]]; then 10 | arg=$(realpath $arg) 11 | fi 12 | printf ",%s" $arg >>$OUTPUT 13 | done 14 | printf "\n" >>$OUTPUT 15 | $HOST_COMPILER $@ 16 | -------------------------------------------------------------------------------- /lib/wrappers/clang: -------------------------------------------------------------------------------- 1 | cc -------------------------------------------------------------------------------- /lib/wrappers/clang++: -------------------------------------------------------------------------------- 1 | cc -------------------------------------------------------------------------------- /lib/wrappers/cpp: -------------------------------------------------------------------------------- 1 | cc -------------------------------------------------------------------------------- /lib/wrappers/g++: -------------------------------------------------------------------------------- 1 | cc -------------------------------------------------------------------------------- /lib/wrappers/gcc: -------------------------------------------------------------------------------- 1 | cc -------------------------------------------------------------------------------- /src/Chisel.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "DeadcodeElimination.h" 8 | #include "FileManager.h" 9 | #include "Frontend.h" 10 | #include "GlobalReduction.h" 11 | #include "IntegrationManager.h" 12 | #include "LocalReduction.h" 13 | #include "OptionManager.h" 14 | #include "Profiler.h" 15 | #include "Reduction.h" 16 | #include "Reformat.h" 17 | #include "Report.h" 18 | #include "StatsManager.h" 19 | #include "Visualization.h" 20 | 21 | void initialize() { 22 | FileManager::Initialize(); 23 | 24 | auto ConsolSink = std::make_shared(); 25 | auto FileSink = std::make_shared( 26 | OptionManager::OutputDir + "/log.txt", true); 27 | auto Logger = std::make_shared( 28 | "Logger", spdlog::sinks_init_list{ConsolSink, FileSink}); 29 | ConsolSink->set_pattern("%v"); 30 | if (OptionManager::Debug) { 31 | ConsolSink->set_level(spdlog::level::debug); 32 | FileSink->set_level(spdlog::level::debug); 33 | Logger->set_level(spdlog::level::debug); 34 | } else { 35 | ConsolSink->set_level(spdlog::level::info); 36 | FileSink->set_level(spdlog::level::info); 37 | Logger->set_level(spdlog::level::info); 38 | } 39 | spdlog::register_logger(Logger); 40 | 41 | IntegrationManager::Initialize(); 42 | Profiler::Initialize(); 43 | spdlog::get("Logger")->info("Oracle: {}", OptionManager::OracleFile); 44 | for (auto &File : OptionManager::InputFiles) 45 | spdlog::get("Logger")->info("Input: {}", File); 46 | spdlog::get("Logger")->info("Output Directory: {}", OptionManager::OutputDir); 47 | } 48 | 49 | void finalize() { 50 | IntegrationManager::Finalize(); 51 | FileManager::Finalize(); 52 | Profiler::Finalize(); 53 | } 54 | 55 | int reduceOneFile(std::string &File) { 56 | spdlog::get("Logger")->info("Reduce File: {}", File); 57 | OptionManager::InputFile = File; 58 | 59 | StatsManager::ComputeStats(OptionManager::InputFile); 60 | int wc0 = std::numeric_limits::max(); 61 | int wc = StatsManager::GetNumOfWords(); 62 | 63 | int Iteration = 0; 64 | while (wc < wc0) { 65 | Iteration++; 66 | spdlog::get("Logger")->info("Iteration {} (Word: {})", Iteration, wc); 67 | wc0 = wc; 68 | 69 | if (!OptionManager::SkipDCE) 70 | DeadCodeElimination::Run(); 71 | 72 | if (!OptionManager::SkipGlobal) { 73 | spdlog::get("Logger")->info("Start global reduction"); 74 | Reduction *GR = new GlobalReduction(); 75 | Frontend::Parse(OptionManager::InputFile, GR); 76 | } 77 | if (!OptionManager::SkipLocal) { 78 | spdlog::get("Logger")->info("Start local reduction"); 79 | Reduction *LR = new LocalReduction(); 80 | Frontend::Parse(OptionManager::InputFile, LR); 81 | } 82 | StatsManager::ComputeStats(OptionManager::InputFile); 83 | wc = StatsManager::GetNumOfWords(); 84 | } 85 | return wc; 86 | } 87 | 88 | int main(int argc, char *argv[]) { 89 | OptionManager::handleOptions(argc, argv); 90 | initialize(); 91 | 92 | Profiler::GetInstance()->beginChisel(); 93 | 94 | StatsManager::ComputeStats(OptionManager::InputFiles); 95 | int wc0 = std::numeric_limits::max(); 96 | int wc = StatsManager::GetNumOfWords(); 97 | 98 | if (OptionManager::Stat) { 99 | StatsManager::Print(); 100 | return 0; 101 | } 102 | 103 | if (OptionManager::XRef) { 104 | Visualization visualization; 105 | for (auto &File : OptionManager::InputFiles) 106 | visualization.generate(File); 107 | return 0; 108 | } 109 | 110 | while (wc < wc0) { 111 | wc0 = wc; 112 | wc = 0; 113 | for (auto &File : OptionManager::InputFiles) 114 | wc += reduceOneFile(File); 115 | } 116 | 117 | for (auto &File : OptionManager::InputFiles) { 118 | OptionManager::InputFile = File; 119 | Transformation *R = new Reformat(); 120 | Frontend::Parse(File, R); 121 | } 122 | 123 | Profiler::GetInstance()->endChisel(); 124 | 125 | Report::print(); 126 | finalize(); 127 | 128 | return 0; 129 | } 130 | -------------------------------------------------------------------------------- /src/core/DeadcodeElimination.cpp: -------------------------------------------------------------------------------- 1 | #include "DeadcodeElimination.h" 2 | 3 | #include "clang/Basic/Diagnostic.h" 4 | #include "clang/Basic/DiagnosticIDs.h" 5 | #include "clang/Basic/LLVM.h" 6 | #include "clang/Basic/TargetInfo.h" 7 | #include "clang/Frontend/CompilerInstance.h" 8 | #include "clang/Frontend/TextDiagnosticBuffer.h" 9 | #include "clang/Frontend/TextDiagnosticPrinter.h" 10 | #include "clang/Frontend/Utils.h" 11 | #include "clang/Lex/Lexer.h" 12 | #include "clang/Lex/Preprocessor.h" 13 | #include "clang/Parse/ParseAST.h" 14 | #include "llvm/ADT/IntrusiveRefCntPtr.h" 15 | #include "llvm/Support/TargetSelect.h" 16 | 17 | #include "FileManager.h" 18 | #include "Frontend.h" 19 | #include "IntegrationManager.h" 20 | #include "OptionManager.h" 21 | #include "SourceManager.h" 22 | 23 | //===----------------------------------------------------------------------===// 24 | // DeadcodeElimination Implementation with oracle testing 25 | //===----------------------------------------------------------------------===// 26 | 27 | void DeadCodeElimination::Run() { 28 | DCEFrontend::Parse(OptionManager::InputFile, new ClangDeadcodeElimination()); 29 | Frontend::Parse(OptionManager::InputFile, new BlockElimination()); 30 | } 31 | 32 | //===----------------------------------------------------------------------===// 33 | // ClangDeadcodeElimination Implementation 34 | //===----------------------------------------------------------------------===// 35 | 36 | void ClangDeadcodeElimination::Initialize(clang::ASTContext &Ctx) { 37 | Transformation::Initialize(Ctx); 38 | CollectionVisitor = new DeadcodeElementCollectionVisitor(this); 39 | } 40 | 41 | bool ClangDeadcodeElimination::HandleTopLevelDecl(clang::DeclGroupRef D) { 42 | for (clang::DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) 43 | CollectionVisitor->TraverseDecl(*I); 44 | return true; 45 | } 46 | 47 | clang::SourceRange 48 | ClangDeadcodeElimination::getRemoveRange(clang::SourceLocation Loc) { 49 | const clang::SourceManager &SM = Context->getSourceManager(); 50 | for (auto Entry : LocationMapping) { 51 | clang::SourceLocation Begin = Entry.second.getBegin(); 52 | clang::SourceLocation End; 53 | if (clang::VarDecl *VD = llvm::dyn_cast(Entry.first)) { 54 | if (VD->hasInit()) { 55 | if (isConstant(VD->getInit())) 56 | End = SourceManager::GetEndLocationUntil(SM, VD->getEndLoc(), 57 | clang::tok::semi); 58 | } else 59 | End = SourceManager::GetEndLocationUntil(SM, VD->getEndLoc(), 60 | clang::tok::semi); 61 | } else if (clang::LabelDecl *LD = 62 | llvm::dyn_cast(Entry.first)) 63 | End = LD->getStmt()->getSubStmt()->getBeginLoc().getLocWithOffset(-1); 64 | 65 | if ((Begin < Loc || Begin == Loc) && (Loc < End || Loc == End)) 66 | return clang::SourceRange(Begin, End); 67 | } 68 | return clang::SourceRange(); 69 | } 70 | 71 | bool ClangDeadcodeElimination::isConstant(clang::Stmt *S) { 72 | if (clang::StringLiteral *L = llvm::dyn_cast(S)) 73 | return true; 74 | if (clang::IntegerLiteral *L = llvm::dyn_cast(S)) 75 | return true; 76 | if (clang::CharacterLiteral *L = llvm::dyn_cast(S)) 77 | return true; 78 | if (clang::CompoundLiteralExpr *L = 79 | llvm::dyn_cast(S)) 80 | return true; 81 | if (clang::FloatingLiteral *L = llvm::dyn_cast(S)) 82 | return true; 83 | if (clang::ImaginaryLiteral *L = llvm::dyn_cast(S)) 84 | return true; 85 | if (clang::CastExpr *L = llvm::dyn_cast(S)) { 86 | clang::Stmt *FirstChild; 87 | for (auto Child : S->children()) { 88 | FirstChild = Child; 89 | break; 90 | } 91 | return isConstant(FirstChild); 92 | } 93 | return false; 94 | } 95 | 96 | void ClangDeadcodeElimination::removeUnusedElements() { 97 | std::vector Ranges; 98 | std::vector Reverts; 99 | const clang::SourceManager &SM = Context->getSourceManager(); 100 | for (auto Loc : UnusedLocations) { 101 | clang::SourceRange Range = getRemoveRange(Loc); 102 | if (Range.isInvalid()) 103 | continue; 104 | clang::SourceLocation Start = Range.getBegin(); 105 | clang::SourceLocation End = Range.getEnd(); 106 | Ranges.emplace_back(Range); 107 | llvm::StringRef Revert = SourceManager::GetSourceText(SM, Start, End); 108 | Reverts.emplace_back(Revert); 109 | removeSourceText(Start, End); 110 | } 111 | TheRewriter.overwriteChangedFiles(); 112 | if (!callOracle()) { 113 | revertRemoval(Ranges,Reverts); 114 | } 115 | } 116 | 117 | bool DeadcodeElementCollectionVisitor::VisitVarDecl(clang::VarDecl *VD) { 118 | if (clang::ParmVarDecl *PVD = llvm::dyn_cast(VD)) 119 | return true; 120 | Consumer->LocationMapping.insert(std::make_pair(VD, VD->getSourceRange())); 121 | return true; 122 | } 123 | 124 | bool DeadcodeElementCollectionVisitor::VisitLabelStmt(clang::LabelStmt *LS) { 125 | Consumer->LocationMapping.insert( 126 | std::make_pair(LS->getDecl(), LS->getDecl()->getSourceRange())); 127 | return true; 128 | } 129 | 130 | bool DCEFrontend::Parse(std::string &InputFile, ClangDeadcodeElimination *R) { 131 | std::unique_ptr CI(new clang::CompilerInstance); 132 | clang::DiagnosticOptions *Opts = new clang::DiagnosticOptions(); 133 | Opts->Warnings.push_back("unused-variable"); 134 | Opts->Warnings.push_back("unused-label"); 135 | clang::TextDiagnosticBuffer *TextDiagBuffer = 136 | new clang::TextDiagnosticBuffer(); 137 | llvm::IntrusiveRefCntPtr D = 138 | CI->createDiagnostics(Opts, TextDiagBuffer); 139 | CI->setDiagnostics(D.get()); 140 | clang::TargetOptions &TO = CI->getTargetOpts(); 141 | TO.Triple = llvm::sys::getDefaultTargetTriple(); 142 | clang::CompilerInvocation &Invocation = CI->getInvocation(); 143 | std::vector Args = 144 | IntegrationManager::GetInstance()->getCC1Args(InputFile); 145 | if (Args.size() > 0) { 146 | clang::CompilerInvocation::CreateFromArgs( 147 | Invocation, &Args[0], &Args[0] + Args.size(), CI->getDiagnostics()); 148 | } 149 | clang::TargetInfo *Target = clang::TargetInfo::CreateTargetInfo( 150 | CI->getDiagnostics(), CI->getInvocation().TargetOpts); 151 | CI->setTarget(Target); 152 | 153 | CI->createFileManager(); 154 | CI->createSourceManager(CI->getFileManager()); 155 | CI->createPreprocessor(clang::TU_Complete); 156 | CI->createASTContext(); 157 | CI->setASTConsumer(std::unique_ptr(R)); 158 | clang::Preprocessor &PP = CI->getPreprocessor(); 159 | PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(), 160 | PP.getLangOpts()); 161 | 162 | if (!CI->InitializeSourceManager( 163 | clang::FrontendInputFile(InputFile, clang::InputKind::C))) { 164 | return false; 165 | } 166 | CI->createSema(clang::TU_Complete, 0); 167 | clang::DiagnosticsEngine &Diag = CI->getDiagnostics(); 168 | CI->getDiagnosticClient().BeginSourceFile(CI->getLangOpts(), 169 | &CI->getPreprocessor()); 170 | ParseAST(CI->getSema()); 171 | 172 | for (clang::TextDiagnosticBuffer::const_iterator DiagnosticIterator = 173 | TextDiagBuffer->warn_begin(); 174 | DiagnosticIterator != TextDiagBuffer->warn_end(); ++DiagnosticIterator) { 175 | if (DiagnosticIterator->second.find("unused variable") == 0 || 176 | DiagnosticIterator->second.find("unused label") == 0) 177 | R->UnusedLocations.emplace_back(DiagnosticIterator->first); 178 | } 179 | R->removeUnusedElements(); 180 | CI->getDiagnosticClient().EndSourceFile(); 181 | return true; 182 | } 183 | 184 | //===----------------------------------------------------------------------===// 185 | // BlockElimination Implementation 186 | //===----------------------------------------------------------------------===// 187 | 188 | void BlockElimination::Initialize(clang::ASTContext &Ctx) { 189 | Transformation::Initialize(Ctx); 190 | Visitor = new BlockEliminationVisitor(this); 191 | } 192 | 193 | bool BlockElimination::HandleTopLevelDecl(clang::DeclGroupRef D) { 194 | for (clang::DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) 195 | Visitor->TraverseDecl(*I); 196 | return true; 197 | } 198 | 199 | void BlockElimination::HandleTranslationUnit(clang::ASTContext &Ctx) { 200 | TheRewriter.overwriteChangedFiles(); 201 | } 202 | 203 | void BlockElimination::removeBlock(clang::CompoundStmt *CS) { 204 | std::vector Ranges_LBrac; 205 | std::vector Reverts_LBrac; 206 | std::vector Ranges_RBrac; 207 | std::vector Reverts_RBrac; 208 | const clang::SourceManager &SM = Context->getSourceManager(); 209 | 210 | clang::SourceLocation Start_LBrac =CS->getLBracLoc(); 211 | clang::SourceLocation End_LBrac =CS->getLBracLoc().getLocWithOffset(1); 212 | clang::SourceRange Range_LBrac(Start_LBrac, End_LBrac); 213 | Ranges_LBrac.emplace_back(Range_LBrac); 214 | llvm::StringRef Revert_LBrac = SourceManager::GetSourceText(SM, Start_LBrac, End_LBrac); 215 | Reverts_LBrac.emplace_back(Revert_LBrac); 216 | removeSourceText(Start_LBrac, End_LBrac); 217 | 218 | clang::SourceLocation Start_RBrac =CS->getRBracLoc(); 219 | clang::SourceLocation End_RBrac =CS->getRBracLoc().getLocWithOffset(1); 220 | clang::SourceRange Range_RBrac(Start_RBrac, End_RBrac); 221 | Ranges_RBrac.emplace_back(Range_RBrac); 222 | llvm::StringRef Revert_RBrac = SourceManager::GetSourceText(SM, Start_RBrac, End_RBrac); 223 | Reverts_RBrac.emplace_back(Revert_RBrac); 224 | removeSourceText(Start_RBrac, End_RBrac); 225 | 226 | TheRewriter.overwriteChangedFiles(); 227 | if (!callOracle()) { 228 | revertRemoval(Ranges_LBrac,Reverts_LBrac); 229 | revertRemoval(Ranges_RBrac,Reverts_RBrac); 230 | } 231 | TheRewriter.overwriteChangedFiles(); 232 | } 233 | 234 | bool BlockEliminationVisitor::VisitFunctionDecl(clang::FunctionDecl *FD) { 235 | Consumer->FunctionBodies.insert(FD->getBody()); 236 | return true; 237 | } 238 | 239 | bool BlockEliminationVisitor::VisitCompoundStmt(clang::CompoundStmt *CS) { 240 | if (CS->size() == 1) { 241 | if (clang::CompoundStmt *SCS = 242 | llvm::dyn_cast(CS->body_front())) 243 | Consumer->removeBlock(SCS); 244 | } 245 | return true; 246 | } 247 | -------------------------------------------------------------------------------- /src/core/Frontend.cpp: -------------------------------------------------------------------------------- 1 | #include "Frontend.h" 2 | 3 | #include "clang/Basic/Diagnostic.h" 4 | #include "clang/Basic/TargetInfo.h" 5 | #include "clang/Frontend/CompilerInstance.h" 6 | #include "clang/Lex/Preprocessor.h" 7 | #include "clang/Parse/ParseAST.h" 8 | 9 | #include "IntegrationManager.h" 10 | 11 | bool Frontend::Parse(std::string &InputFile, clang::ASTConsumer *R) { 12 | std::unique_ptr CI(new clang::CompilerInstance); 13 | CI->createDiagnostics(); 14 | clang::TargetOptions &TO = CI->getTargetOpts(); 15 | TO.Triple = llvm::sys::getDefaultTargetTriple(); 16 | clang::CompilerInvocation &Invocation = CI->getInvocation(); 17 | std::vector Args = 18 | IntegrationManager::GetInstance()->getCC1Args(InputFile); 19 | clang::CompilerInvocation::CreateFromArgs( 20 | Invocation, &Args[0], &Args[0] + Args.size(), CI->getDiagnostics()); 21 | clang::TargetInfo *Target = clang::TargetInfo::CreateTargetInfo( 22 | CI->getDiagnostics(), CI->getInvocation().TargetOpts); 23 | CI->setTarget(Target); 24 | 25 | CI->createFileManager(); 26 | CI->createSourceManager(CI->getFileManager()); 27 | CI->createPreprocessor(clang::TU_Complete); 28 | CI->createASTContext(); 29 | 30 | CI->setASTConsumer(std::unique_ptr(R)); 31 | clang::Preprocessor &PP = CI->getPreprocessor(); 32 | PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(), 33 | PP.getLangOpts()); 34 | 35 | if (!CI->InitializeSourceManager( 36 | clang::FrontendInputFile(InputFile, clang::InputKind::C))) { 37 | return false; 38 | } 39 | 40 | CI->createSema(clang::TU_Complete, 0); 41 | clang::DiagnosticsEngine &Diag = CI->getDiagnostics(); 42 | Diag.setSuppressAllDiagnostics(true); 43 | Diag.setIgnoreAllWarnings(true); 44 | 45 | CI->getDiagnosticClient().BeginSourceFile(CI->getLangOpts(), 46 | &CI->getPreprocessor()); 47 | ParseAST(CI->getSema()); 48 | CI->getDiagnosticClient().EndSourceFile(); 49 | return true; 50 | } 51 | -------------------------------------------------------------------------------- /src/core/GlobalReduction.cpp: -------------------------------------------------------------------------------- 1 | #include "GlobalReduction.h" 2 | 3 | #include 4 | 5 | #include "FileManager.h" 6 | #include "OptionManager.h" 7 | #include "Profiler.h" 8 | #include "SourceManager.h" 9 | 10 | void GlobalReduction::Initialize(clang::ASTContext &Ctx) { 11 | Reduction::Initialize(Ctx); 12 | CollectionVisitor = new GlobalElementCollectionVisitor(this); 13 | } 14 | 15 | bool GlobalReduction::HandleTopLevelDecl(clang::DeclGroupRef D) { 16 | clang::SourceManager &SM = Context->getSourceManager(); 17 | for (clang::DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { 18 | if (SourceManager::IsInHeader(SM, *I)) 19 | continue; 20 | CollectionVisitor->TraverseDecl(*I); 21 | } 22 | return true; 23 | } 24 | 25 | void GlobalReduction::HandleTranslationUnit(clang::ASTContext &Ctx) { 26 | std::vector> elements; 27 | elements.resize(Decls.size()); 28 | std::transform(Decls.begin(), Decls.end(), elements.begin(), CastElement); 29 | doDeltaDebugging(elements); 30 | } 31 | 32 | DDElement GlobalReduction::CastElement(clang::Decl *D) { return D; } 33 | 34 | bool GlobalReduction::callOracle() { 35 | Profiler::GetInstance()->incrementGlobalReductionCounter(); 36 | 37 | if (Reduction::callOracle()) { 38 | Profiler::GetInstance()->incrementSuccessfulGlobalReductionCounter(); 39 | FileManager::GetInstance()->saveTemp("global", true); 40 | return true; 41 | } else { 42 | FileManager::GetInstance()->saveTemp("global", false); 43 | return false; 44 | } 45 | } 46 | 47 | bool GlobalReduction::test(DDElementVector &ToBeRemoved) { 48 | const clang::SourceManager &SM = Context->getSourceManager(); 49 | std::vector Ranges; 50 | std::vector Reverts; 51 | 52 | for (auto const &Element : ToBeRemoved) { 53 | if (Element.isNull()) 54 | continue; 55 | 56 | clang::Decl *D = Element.get(); 57 | 58 | clang::SourceLocation Start = D->getSourceRange().getBegin(); 59 | clang::SourceLocation End; 60 | 61 | if (clang::FunctionDecl *FD = llvm::dyn_cast(D)) { 62 | if (FD->isThisDeclarationADefinition()) 63 | End = FD->getSourceRange().getEnd(); 64 | } else if (clang::EmptyDecl *ED = llvm::dyn_cast(D)) { 65 | End = ED->getSourceRange().getEnd(); 66 | } else { 67 | End = SourceManager::GetEndLocationUntil(SM, D->getEndLoc(), 68 | clang::tok::semi); 69 | } 70 | 71 | if (Start.isMacroID()) 72 | Start = SM.getFileLoc(Start); 73 | if (End.isMacroID()) 74 | End = SM.getFileLoc(End); 75 | 76 | if (End.isInvalid() || Start.isInvalid()) 77 | return false; 78 | 79 | clang::SourceRange Range(Start, End); 80 | Ranges.emplace_back(Range); 81 | llvm::StringRef Revert = SourceManager::GetSourceText(SM, Start, End); 82 | Reverts.emplace_back(Revert); 83 | removeSourceText(Start, End); 84 | } 85 | 86 | TheRewriter.overwriteChangedFiles(); 87 | 88 | if (callOracle()) { 89 | return true; 90 | } else { 91 | for (int i = 0; i < Reverts.size(); i++) 92 | TheRewriter.ReplaceText(Ranges[i], Reverts[i]); 93 | TheRewriter.overwriteChangedFiles(); 94 | return false; 95 | } 96 | } 97 | 98 | bool GlobalReduction::isInvalidChunk(DDElementVector &Chunk) { 99 | if (OptionManager::SkipGlobalDep) 100 | return false; 101 | return !(std::all_of(std::begin(Chunk), std::end(Chunk), [&](DDElement i) { 102 | return !UseInfo[i.get()]; 103 | })); 104 | } 105 | 106 | bool GlobalElementCollectionVisitor::VisitDeclRefExpr(clang::DeclRefExpr *DRE) { 107 | auto *D = DRE->getDecl(); 108 | if (clang::VarDecl *VD = llvm::dyn_cast(D)) { 109 | if (VD->hasGlobalStorage()) 110 | Consumer->UseInfo[VD] = true; 111 | } else if (clang::FunctionDecl *FD = llvm::dyn_cast(D)) { 112 | Consumer->UseInfo[FD->getDefinition()] = true; 113 | } 114 | 115 | return true; 116 | } 117 | 118 | bool GlobalElementCollectionVisitor::VisitFunctionDecl( 119 | clang::FunctionDecl *FD) { 120 | spdlog::get("Logger")->debug("Visit Function Decl: {}", 121 | FD->getNameInfo().getAsString()); 122 | // hard rule : must contain main() 123 | if (FD->isMain() && !OptionManager::SkipGlobalDep) 124 | return true; 125 | Consumer->Decls.emplace_back(FD->getDefinition()); 126 | return true; 127 | } 128 | 129 | bool GlobalElementCollectionVisitor::VisitVarDecl(clang::VarDecl *VD) { 130 | if (VD->hasGlobalStorage()) { 131 | spdlog::get("Logger")->debug("Visit Var Decl: {}", VD->getNameAsString()); 132 | Consumer->Decls.emplace_back(VD); 133 | } 134 | return true; 135 | } 136 | 137 | bool GlobalElementCollectionVisitor::VisitEmptyDecl(clang::EmptyDecl *ED) { 138 | spdlog::get("Logger")->debug("Visit Empty Decl"); 139 | Consumer->Decls.emplace_back(ED); 140 | return true; 141 | } 142 | -------------------------------------------------------------------------------- /src/core/LocalReduction.cpp: -------------------------------------------------------------------------------- 1 | #include "LocalReduction.h" 2 | 3 | #include 4 | 5 | #include "clang/Lex/Lexer.h" 6 | 7 | #include "FileManager.h" 8 | #include "OptionManager.h" 9 | #include "Profiler.h" 10 | #include "SourceManager.h" 11 | 12 | using BinaryOperator = clang::BinaryOperator; 13 | using BreakStmt = clang::BreakStmt; 14 | using CallExpr = clang::CallExpr; 15 | using ContinueStmt = clang::ContinueStmt; 16 | using CompoundStmt = clang::CompoundStmt; 17 | using DeclGroupRef = clang::DeclGroupRef; 18 | using DeclStmt = clang::DeclStmt; 19 | using FunctionDecl = clang::FunctionDecl; 20 | using GotoStmt = clang::GotoStmt; 21 | using IfStmt = clang::IfStmt; 22 | using LabelStmt = clang::LabelStmt; 23 | using ReturnStmt = clang::ReturnStmt; 24 | using SourceRange = clang::SourceRange; 25 | using SourceLocation = clang::SourceLocation; 26 | using Stmt = clang::Stmt; 27 | using UnaryOperator = clang::UnaryOperator; 28 | using WhileStmt = clang::WhileStmt; 29 | using VarDecl = clang::VarDecl; 30 | using Decl = clang::Decl; 31 | using LabelDecl = clang::LabelDecl; 32 | using Expr = clang::Expr; 33 | using DeclRefExpr = clang::DeclRefExpr; 34 | using ForStmt = clang::ForStmt; 35 | using SwitchStmt = clang::SwitchStmt; 36 | using DoStmt = clang::DoStmt; 37 | 38 | void LocalReduction::Initialize(clang::ASTContext &Ctx) { 39 | Reduction::Initialize(Ctx); 40 | CollectionVisitor = new LocalElementCollectionVisitor(this); 41 | } 42 | 43 | bool LocalReduction::HandleTopLevelDecl(DeclGroupRef D) { 44 | clang::SourceManager &SM = Context->getSourceManager(); 45 | for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { 46 | if (SourceManager::IsInHeader(SM, *I)) 47 | continue; 48 | CollectionVisitor->TraverseDecl(*I); 49 | } 50 | return true; 51 | } 52 | 53 | void LocalReduction::HandleTranslationUnit(clang::ASTContext &Ctx) { 54 | for (auto const &FD : Functions) { 55 | spdlog::get("Logger")->info("Reduce {} at {}", 56 | FD->getNameInfo().getAsString(), 57 | OptionManager::InputFile); 58 | Queue.push(FD->getBody()); 59 | 60 | CurrentFunction = FD; 61 | 62 | while (!Queue.empty()) { 63 | Stmt *S = Queue.front(); 64 | Queue.pop(); 65 | doHierarchicalDeltaDebugging(S); 66 | } 67 | } 68 | } 69 | 70 | DDElement LocalReduction::CastElement(Stmt *S) { return S; } 71 | 72 | bool LocalReduction::callOracle() { 73 | Profiler::GetInstance()->incrementLocalReductionCounter(); 74 | 75 | if (Reduction::callOracle()) { 76 | Profiler::GetInstance()->incrementSuccessfulLocalReductionCounter(); 77 | FileManager::GetInstance()->saveTemp("local", true); 78 | return true; 79 | } else { 80 | FileManager::GetInstance()->saveTemp("local", false); 81 | return false; 82 | } 83 | } 84 | 85 | bool LocalReduction::test(DDElementVector &ToBeRemoved) { 86 | const clang::SourceManager &SM = Context->getSourceManager(); 87 | std::vector Ranges; 88 | std::vector Reverts; 89 | 90 | for (auto Element : ToBeRemoved) { 91 | if (Element.isNull()) 92 | continue; 93 | 94 | clang::Stmt *S = Element.get(); 95 | clang::SourceLocation Start = SourceManager::GetBeginOfStmt(Context, S); 96 | clang::SourceLocation End = SourceManager::GetEndOfStmt(Context, S); 97 | 98 | if (End.isInvalid() || Start.isInvalid()) 99 | return false; 100 | 101 | SourceRange Range(Start, End); 102 | Ranges.emplace_back(Range); 103 | llvm::StringRef Revert = SourceManager::GetSourceText(SM, Start, End); 104 | Reverts.emplace_back(Revert); 105 | removeSourceText(Start, End); 106 | } 107 | TheRewriter.overwriteChangedFiles(); 108 | if (callOracle()) { 109 | for (auto &E : ToBeRemoved) { 110 | auto Children = getAllChildren(E.get()); 111 | RemovedElements.insert(Children.begin(), Children.end()); 112 | } 113 | return true; 114 | } else { 115 | for (int i = 0; i < Reverts.size(); i++) 116 | TheRewriter.ReplaceText(Ranges[i], Reverts[i]); 117 | TheRewriter.overwriteChangedFiles(); 118 | return false; 119 | } 120 | 121 | return false; 122 | } 123 | 124 | int LocalReduction::countReturnStmts(std::set &Elements) { 125 | int NumReturns = 0; 126 | for (auto const &E : Elements) 127 | if (ReturnStmt *RS = llvm::dyn_cast(E)) 128 | NumReturns++; 129 | return NumReturns; 130 | } 131 | 132 | bool LocalReduction::noReturn(std::set &FunctionStmts, 133 | std::set &AllRemovedStmts) { 134 | if (CurrentFunction->getReturnType().getTypePtr()->isVoidType()) 135 | return false; 136 | int FunctionReturns = countReturnStmts(FunctionStmts); 137 | int RemovedReturns = countReturnStmts(AllRemovedStmts); 138 | if (FunctionReturns == 0 || RemovedReturns == 0) 139 | return false; 140 | if (countReturnStmts(FunctionStmts) == countReturnStmts(AllRemovedStmts)) 141 | return true; 142 | return false; 143 | } 144 | 145 | bool LocalReduction::danglingLabel(std::set &Remaining) { 146 | std::set LabelDefs; 147 | std::set LabelUses; 148 | 149 | for (auto const &S : Remaining) { 150 | if (!S) 151 | continue; 152 | if (GotoStmt *GS = llvm::dyn_cast(S)) 153 | LabelUses.insert(GS->getLabel()->getStmt()); 154 | else if (LabelStmt *LS = llvm::dyn_cast(S)) 155 | LabelDefs.insert(LS); 156 | } 157 | 158 | return !(std::includes(LabelDefs.begin(), LabelDefs.end(), LabelUses.begin(), 159 | LabelUses.end())); 160 | } 161 | 162 | std::vector LocalReduction::getDeclRefExprs(Expr *E) { 163 | std::vector result; 164 | std::vector Children = getAllChildren(E); 165 | for (auto const &S : Children) { 166 | if (!S) 167 | continue; 168 | if (DeclRefExpr *DRE = llvm::dyn_cast(S)) 169 | result.emplace_back(DRE); 170 | } 171 | return result; 172 | } 173 | void LocalReduction::addDefUse(DeclRefExpr *DRE, std::set &DU) { 174 | if (VarDecl *VD = llvm::dyn_cast(DRE->getDecl())) { 175 | if (auto T = llvm::dyn_cast_or_null( 176 | VD->getType().getTypePtr())) 177 | return; 178 | if (VD->isLocalVarDeclOrParm() || VD->isStaticLocal()) 179 | DU.insert(DRE->getDecl()); 180 | } 181 | } 182 | 183 | bool LocalReduction::brokenDependency(std::set &Remaining) { 184 | std::set Defs, Uses; 185 | for (auto const &S : Remaining) { 186 | if (!S) 187 | continue; 188 | if (BinaryOperator *BO = llvm::dyn_cast(S)) { 189 | if (BO->isCompoundAssignmentOp() || BO->isShiftAssignOp()) { 190 | for (auto C : getDeclRefExprs(BO->getLHS())) { 191 | addDefUse(C, Defs); 192 | addDefUse(C, Uses); 193 | } 194 | for (auto C : getDeclRefExprs(BO->getRHS())) 195 | addDefUse(C, Uses); 196 | } else if (BO->isAssignmentOp()) { 197 | for (auto C : getDeclRefExprs(BO->getLHS())) 198 | addDefUse(C, Defs); 199 | for (auto C : getDeclRefExprs(BO->getRHS())) 200 | addDefUse(C, Uses); 201 | } else { 202 | for (auto C : getDeclRefExprs(BO->getLHS())) 203 | addDefUse(C, Uses); 204 | for (auto C : getDeclRefExprs(BO->getRHS())) 205 | addDefUse(C, Uses); 206 | } 207 | } else if (UnaryOperator *UO = llvm::dyn_cast(S)) { 208 | switch (UO->getOpcode()) { 209 | case clang::UO_PostInc: 210 | case clang::UO_PostDec: 211 | case clang::UO_PreInc: 212 | case clang::UO_PreDec: 213 | for (auto C : getDeclRefExprs(UO->getSubExpr())) { 214 | addDefUse(C, Defs); 215 | addDefUse(C, Uses); 216 | } 217 | break; 218 | case clang::UO_AddrOf: 219 | for (auto C : getDeclRefExprs(UO->getSubExpr())) 220 | addDefUse(C, Defs); 221 | break; 222 | case clang::UO_Plus: 223 | case clang::UO_Minus: 224 | case clang::UO_Not: 225 | case clang::UO_Deref: 226 | case clang::UO_LNot: 227 | for (auto C : getDeclRefExprs(UO->getSubExpr())) 228 | addDefUse(C, Uses); 229 | } 230 | } else if (DeclStmt *DS = llvm::dyn_cast(S)) { 231 | for (auto D : DS->decls()) 232 | if (VarDecl *VD = llvm::dyn_cast(D)) 233 | if (VD->hasInit()) 234 | Defs.insert(D); 235 | } else if (CallExpr *CE = llvm::dyn_cast(S)) { 236 | for (int I = 0; I < CE->getNumArgs(); I++) 237 | for (auto C : getDeclRefExprs(CE->getArg(I))) 238 | addDefUse(C, Uses); 239 | } else if (ReturnStmt *RS = llvm::dyn_cast(S)) { 240 | if (!CurrentFunction->getReturnType().getTypePtr()->isVoidType()) 241 | for (auto C : getDeclRefExprs(RS->getRetValue())) 242 | addDefUse(C, Uses); 243 | } 244 | for (auto P : CurrentFunction->parameters()) 245 | Defs.insert(P); 246 | } 247 | return !(std::includes(Defs.begin(), Defs.end(), Uses.begin(), Uses.end())); 248 | } 249 | 250 | std::set LocalReduction::toSet(std::vector &Vec) { 251 | std::set S(Vec.begin(), Vec.end()); 252 | return S; 253 | } 254 | 255 | std::set LocalReduction::setDifference(std::set &A, 256 | std::set &B) { 257 | std::set Result; 258 | std::set_difference(A.begin(), A.end(), B.begin(), B.end(), 259 | std::inserter(Result, Result.begin())); 260 | return Result; 261 | } 262 | 263 | bool LocalReduction::isInvalidChunk(DDElementVector &Chunk) { 264 | if (OptionManager::SkipLocalDep) 265 | return false; 266 | std::vector FunctionStmts = 267 | getAllChildren(CurrentFunction->getBody()); 268 | std::vector AllRemovedStmts; 269 | for (auto S : Chunk) { 270 | auto Children = getAllChildren(S.get()); 271 | AllRemovedStmts.insert(AllRemovedStmts.end(), Children.begin(), 272 | Children.end()); 273 | } 274 | auto TempFSet = toSet(FunctionStmts); 275 | auto FSet = setDifference(TempFSet, RemovedElements); 276 | auto ASet = toSet(AllRemovedStmts); 277 | auto Remaining = setDifference(FSet, ASet); 278 | 279 | if (noReturn(FSet, ASet)) 280 | return true; 281 | if (danglingLabel(Remaining)) 282 | return true; 283 | if (brokenDependency(Remaining)) 284 | return true; 285 | return false; 286 | } 287 | 288 | void LocalReduction::doHierarchicalDeltaDebugging(Stmt *S) { 289 | if (S == NULL) 290 | return; 291 | clang::SourceLocation Start = SourceManager::GetBeginOfStmt(Context, S); 292 | const clang::SourceManager &SM = Context->getSourceManager(); 293 | std::string Loc = Start.printToString(SM); 294 | if (IfStmt *IS = llvm::dyn_cast(S)) { 295 | spdlog::get("Logger")->debug("HDD IF at " + Loc); 296 | reduceIf(IS); 297 | } else if (WhileStmt *WS = llvm::dyn_cast(S)) { 298 | spdlog::get("Logger")->debug("HDD WHILE at " + Loc); 299 | reduceWhile(WS); 300 | } else if (CompoundStmt *CS = llvm::dyn_cast(S)) { 301 | spdlog::get("Logger")->debug("HDD Compound at " + Loc); 302 | reduceCompound(CS); 303 | } else if (LabelStmt *LS = llvm::dyn_cast(S)) { 304 | spdlog::get("Logger")->debug("HDD Label at " + Loc); 305 | reduceLabel(LS); 306 | } else if (ForStmt *FS = llvm::dyn_cast(S)) { 307 | spdlog::get("Logger")->debug("HDD FOR at " + Loc); 308 | reduceFor(FS); 309 | } else if (SwitchStmt *SS = llvm::dyn_cast(S)) { 310 | spdlog::get("Logger")->debug("HDD SWITCH at " + Loc); 311 | reduceSwitch(SS); 312 | } else if (DoStmt *DS = llvm::dyn_cast(S)) { 313 | spdlog::get("Logger")->debug("HDD DO/WHILE at " + Loc); 314 | reduceDoWhile(DS); 315 | } 316 | } 317 | 318 | std::vector LocalReduction::getBodyStatements(CompoundStmt *CS) { 319 | std::vector Stmts; 320 | for (auto S : CS->body()) 321 | if (S != NULL) 322 | Stmts.emplace_back(S); 323 | return Stmts; 324 | } 325 | 326 | void LocalReduction::reduceSwitch(SwitchStmt *SS) { 327 | const clang::SourceManager &SM = Context->getSourceManager(); 328 | auto Body = SS->getBody(); 329 | SourceLocation BeginSwitch = SourceManager::GetBeginOfStmt(Context, SS); 330 | SourceLocation EndSwitch = SourceManager::GetEndOfStmt(Context, SS); 331 | 332 | if (BeginSwitch.isInvalid() || EndSwitch.isInvalid()) { 333 | spdlog::get("Logger")->warn( 334 | "Invalid location:\nBeginSwitch: {}\nEndSwitch: {}", 335 | BeginSwitch.printToString(SM), EndSwitch.printToString(SM)); 336 | return; 337 | } 338 | 339 | std::vector Cases; 340 | for (clang::SwitchCase *SC = SS->getSwitchCaseList(); SC != NULL; 341 | SC = SC->getNextSwitchCase()) { 342 | Cases.insert(Cases.begin(), SC); 343 | } 344 | for (int I = 0; I < Cases.size(); I++) { 345 | SourceLocation CurrLoc = 346 | SourceManager::GetRealLocation(Context, Cases[I]->getKeywordLoc()); 347 | SourceLocation NextLoc; 348 | if (I < Cases.size() - 1) { 349 | NextLoc = 350 | SourceManager::GetRealLocation(Context, Cases[I + 1]->getKeywordLoc()) 351 | .getLocWithOffset(-1); 352 | } else { 353 | NextLoc = EndSwitch.getLocWithOffset(-1); 354 | } 355 | llvm::StringRef Revert = SourceManager::GetSourceText(SM, CurrLoc, NextLoc); 356 | removeSourceText(CurrLoc, NextLoc); 357 | TheRewriter.overwriteChangedFiles(); 358 | if (callOracle()) { 359 | auto TempChildren = getAllChildren(Cases[I]); 360 | RemovedElements.insert(TempChildren.begin(), TempChildren.end()); 361 | } else { 362 | TheRewriter.ReplaceText(SourceRange(CurrLoc, NextLoc), Revert); 363 | TheRewriter.overwriteChangedFiles(); 364 | Queue.push(Cases[I]); 365 | } 366 | } 367 | } 368 | 369 | void LocalReduction::reduceIf(IfStmt *IS) { 370 | const clang::SourceManager &SM = Context->getSourceManager(); 371 | SourceLocation BeginIf = SourceManager::GetBeginOfStmt(Context, IS); 372 | SourceLocation EndIf = SourceManager::GetEndOfStmt(Context, IS); 373 | SourceLocation EndCond = SourceManager::GetEndOfCond(SM, IS->getCond()); 374 | SourceLocation EndThen = SourceManager::GetEndOfStmt(Context, IS->getThen()); 375 | 376 | if (BeginIf.isInvalid() || EndIf.isInvalid() || EndCond.isInvalid() || 377 | EndThen.isInvalid()) { 378 | spdlog::get("Logger")->warn( 379 | "Invalid location:\nBeginIf: {}\nEndIf: {}\nEndCond: {}\nEndThen: {}", 380 | BeginIf.printToString(SM), EndIf.printToString(SM), 381 | EndCond.printToString(SM), EndThen.printToString(SM)); 382 | return; 383 | } 384 | 385 | llvm::StringRef RevertIf = SourceManager::GetSourceText(SM, BeginIf, EndIf); 386 | 387 | if (IS->getElse()) { 388 | SourceLocation ElseLoc = IS->getElseLoc(); 389 | if (ElseLoc.isInvalid()) 390 | return; 391 | 392 | removeSourceText(BeginIf, EndCond); 393 | removeSourceText(ElseLoc, EndIf); 394 | TheRewriter.overwriteChangedFiles(); 395 | if (callOracle()) { 396 | Queue.push(IS->getThen()); 397 | std::vector ElseVec = {IS->getCond(), IS->getElse()}; 398 | for (auto C : ElseVec) { 399 | auto Children = getAllChildren(C); 400 | RemovedElements.insert(Children.begin(), Children.end()); 401 | } 402 | } else { 403 | TheRewriter.ReplaceText(SourceRange(BeginIf, EndIf), RevertIf); 404 | removeSourceText(BeginIf, ElseLoc.getLocWithOffset(3)); 405 | TheRewriter.overwriteChangedFiles(); 406 | if (callOracle()) { 407 | Queue.push(IS->getElse()); 408 | std::vector ThenVec = {IS->getCond(), IS->getThen()}; 409 | for (auto C : ThenVec) { 410 | auto Children = getAllChildren(C); 411 | RemovedElements.insert(Children.begin(), Children.end()); 412 | } 413 | } else { 414 | TheRewriter.ReplaceText(SourceRange(BeginIf, EndIf), RevertIf); 415 | TheRewriter.overwriteChangedFiles(); 416 | Queue.push(IS->getThen()); 417 | Queue.push(IS->getElse()); 418 | } 419 | } 420 | } else { 421 | removeSourceText(BeginIf, EndCond); 422 | TheRewriter.overwriteChangedFiles(); 423 | if (callOracle()) { 424 | auto Children = getAllChildren(IS->getCond()); 425 | RemovedElements.insert(Children.begin(), Children.end()); 426 | } else { 427 | TheRewriter.ReplaceText(SourceRange(BeginIf, EndIf), RevertIf); 428 | TheRewriter.overwriteChangedFiles(); 429 | } 430 | Queue.push(IS->getThen()); 431 | } 432 | } 433 | 434 | void LocalReduction::reduceFor(ForStmt *FS) { 435 | const clang::SourceManager &SM = Context->getSourceManager(); 436 | auto Body = FS->getBody(); 437 | SourceLocation BeginFor = SourceManager::GetBeginOfStmt(Context, FS); 438 | SourceLocation EndFor = SourceManager::GetEndOfStmt(Context, FS); 439 | SourceLocation EndCond = FS->getRParenLoc(); 440 | 441 | if (BeginFor.isInvalid() || EndFor.isInvalid() || EndCond.isInvalid()) { 442 | spdlog::get("Logger")->warn( 443 | "Invalid location:\nBeginFor: {}\nEndFor: {}\nEndCond: {}", 444 | BeginFor.printToString(SM), EndFor.printToString(SM), 445 | EndCond.printToString(SM)); 446 | return; 447 | } 448 | 449 | llvm::StringRef Revert = SourceManager::GetSourceText(SM, BeginFor, EndFor); 450 | 451 | removeSourceText(BeginFor, EndCond); 452 | TheRewriter.overwriteChangedFiles(); 453 | if (callOracle()) { 454 | std::vector ForVec; 455 | if (FS->getCond()) 456 | ForVec.emplace_back(FS->getCond()); 457 | if (FS->getInit()) 458 | ForVec.emplace_back(FS->getInit()); 459 | if (FS->getInc()) 460 | ForVec.emplace_back(FS->getInc()); 461 | for (auto C : ForVec) { 462 | auto Children = getAllChildren(C); 463 | RemovedElements.insert(Children.begin(), Children.end()); 464 | } 465 | } else { 466 | TheRewriter.ReplaceText(SourceRange(BeginFor, EndFor), Revert); 467 | TheRewriter.overwriteChangedFiles(); 468 | } 469 | Queue.push(Body); 470 | } 471 | 472 | void LocalReduction::reduceWhile(WhileStmt *WS) { 473 | const clang::SourceManager &SM = Context->getSourceManager(); 474 | auto Body = WS->getBody(); 475 | SourceLocation BeginWhile = SourceManager::GetBeginOfStmt(Context, WS); 476 | SourceLocation EndWhile = SourceManager::GetEndOfStmt(Context, WS); 477 | SourceLocation EndCond = SourceManager::GetEndOfCond(SM, WS->getCond()); 478 | 479 | if (BeginWhile.isInvalid() || EndWhile.isInvalid() || EndCond.isInvalid()) { 480 | spdlog::get("Logger")->warn("Invalid location:\nBeginWhile: {}\nEndWhile: " 481 | "{}\nEndCond: {}", 482 | BeginWhile.printToString(SM), 483 | EndWhile.printToString(SM), 484 | EndCond.printToString(SM)); 485 | return; 486 | } 487 | 488 | llvm::StringRef Revert = 489 | SourceManager::GetSourceText(SM, BeginWhile, EndWhile); 490 | 491 | removeSourceText(BeginWhile, EndCond); 492 | TheRewriter.overwriteChangedFiles(); 493 | if (callOracle()) { 494 | auto Children = getAllChildren(WS->getCond()); 495 | RemovedElements.insert(Children.begin(), Children.end()); 496 | } else { 497 | TheRewriter.ReplaceText(SourceRange(BeginWhile, EndWhile), Revert); 498 | TheRewriter.overwriteChangedFiles(); 499 | } 500 | Queue.push(Body); 501 | } 502 | 503 | void LocalReduction::reduceDoWhile(DoStmt *DS) { 504 | const clang::SourceManager &SM = Context->getSourceManager(); 505 | auto Body = DS->getBody(); 506 | SourceLocation BeginDo = SourceManager::GetBeginOfStmt(Context, DS); 507 | SourceLocation EndDo = SourceManager::GetEndOfStmt(Context, DS); 508 | SourceLocation EndCond = SourceManager::GetEndOfCond(SM, DS->getCond()); 509 | 510 | if (BeginDo.isInvalid() || EndDo.isInvalid() || EndCond.isInvalid()) { 511 | spdlog::get("Logger")->warn("Invalid location:\nBeginDo: {}\nEndDo: " 512 | "{}\nEndCond: {}", 513 | BeginDo.printToString(SM), 514 | EndDo.printToString(SM), 515 | EndCond.printToString(SM)); 516 | return; 517 | } 518 | 519 | llvm::StringRef Revert = SourceManager::GetSourceText(SM, BeginDo, EndDo); 520 | 521 | removeSourceText(BeginDo, BeginDo.getLocWithOffset(1)); 522 | removeSourceText(DS->getWhileLoc(), EndDo); 523 | TheRewriter.overwriteChangedFiles(); 524 | if (callOracle()) { 525 | auto Children = getAllChildren(DS->getCond()); 526 | RemovedElements.insert(Children.begin(), Children.end()); 527 | } else { 528 | TheRewriter.ReplaceText(SourceRange(BeginDo, EndDo), Revert); 529 | TheRewriter.overwriteChangedFiles(); 530 | } 531 | Queue.push(Body); 532 | } 533 | 534 | void LocalReduction::reduceCompound(CompoundStmt *CS) { 535 | auto Stmts = getBodyStatements(CS); 536 | filterElements(Stmts); 537 | 538 | DDElementVector Elements; 539 | if (Stmts.size() == 0) 540 | return; 541 | 542 | Elements.resize(Stmts.size()); 543 | std::transform(Stmts.begin(), Stmts.end(), Elements.begin(), CastElement); 544 | 545 | DDElementSet Removed = doDeltaDebugging(Elements); 546 | for (auto S : Stmts) { 547 | if (Removed.find(S) == Removed.end()) 548 | Queue.push(S); 549 | } 550 | } 551 | 552 | void LocalReduction::reduceLabel(LabelStmt *LS) { 553 | Queue.push(LS->getSubStmt()); 554 | } 555 | 556 | void LocalReduction::filterElements(std::vector &Vec) { 557 | auto I = Vec.begin(); 558 | while (I != Vec.end()) { 559 | clang::Stmt *S = *I; 560 | if (DeclStmt *DS = llvm::dyn_cast(S)) 561 | Vec.erase(I); 562 | else if (clang::NullStmt *NS = llvm::dyn_cast(S)) 563 | Vec.erase(I); 564 | else 565 | I++; 566 | } 567 | } 568 | 569 | bool LocalElementCollectionVisitor::VisitFunctionDecl(FunctionDecl *FD) { 570 | spdlog::get("Logger")->debug("Visit Function Decl: {}", 571 | FD->getNameInfo().getAsString()); 572 | if (FD->isThisDeclarationADefinition()) 573 | Consumer->Functions.emplace_back(FD); 574 | return true; 575 | } 576 | -------------------------------------------------------------------------------- /src/core/ProbabilisticModel.cpp: -------------------------------------------------------------------------------- 1 | #include "ProbabilisticModel.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "OptionManager.h" 11 | #include "Profiler.h" 12 | 13 | void ProbabilisticModel::initialize(DDElementVector &Source) { 14 | if (OptionManager::SkipLearning) 15 | return; 16 | clear(); 17 | TrainingSet = arma::mat(Source.size(), 1, arma::fill::ones); 18 | TrainingLabels = arma::Row(1, arma::fill::zeros); 19 | } 20 | 21 | void ProbabilisticModel::clear() { 22 | if (OptionManager::SkipLearning) 23 | return; 24 | TrainingSet.reset(); 25 | TrainingLabels.reset(); 26 | } 27 | 28 | void ProbabilisticModel::train(int Iteration) { 29 | if (OptionManager::SkipLearning) 30 | return; 31 | Profiler::GetInstance()->beginLearning(); 32 | bool ShouldTrain = 33 | !(Iteration > 100 && Iteration % (Iteration / 100 + 1) != 0); 34 | if ((!OptionManager::SkipDelayLearning && ShouldTrain) || 35 | OptionManager::SkipDelayLearning) { 36 | MyDecisionTree.Train(TrainingSet, TrainingLabels, 2, 1); 37 | } 38 | Profiler::GetInstance()->endLearning(); 39 | } 40 | 41 | void ProbabilisticModel::addForTraining(DDElementVector &Source, 42 | DDElementVector &Chunk, bool Label) { 43 | if (OptionManager::SkipLearning) 44 | return; 45 | Profiler::GetInstance()->beginLearning(); 46 | arma::mat Diff = createFeatureVector(Source, Chunk); 47 | TrainingSet.resize(TrainingSet.n_rows, TrainingSet.n_cols + 1); 48 | TrainingSet.col(TrainingSet.n_cols - 1) = Diff; 49 | TrainingLabels.resize(TrainingLabels.n_elem + 1); 50 | TrainingLabels(TrainingLabels.n_elem - 1) = Label ? 0 : 1; 51 | Profiler::GetInstance()->endLearning(); 52 | } 53 | 54 | arma::uvec 55 | ProbabilisticModel::sortCandidates(DDElementVector &Source, 56 | std::vector &Chunks) { 57 | arma::uvec EmptyVector; 58 | if (OptionManager::SkipLearning) 59 | return EmptyVector; 60 | if (Source.size() == 0 || Chunks.size() == 0) 61 | return EmptyVector; 62 | Profiler::GetInstance()->beginLearning(); 63 | arma::mat Probabilities; 64 | arma::Row Predictions; 65 | 66 | arma::mat Data(Source.size(), Chunks.size(), arma::fill::ones); 67 | for (int I = 0; I < Chunks.size(); I++) 68 | Data.col(I) = createFeatureVector(Source, Chunks[I]); 69 | MyDecisionTree.Classify(Data, Predictions, Probabilities); 70 | arma::uvec SortedIndex = sort_index(Probabilities.row(0), "descend"); 71 | if (Chunks.size() == Source.size() || Chunks.size() == Source.size() - 1) 72 | return SortedIndex; 73 | Profiler::GetInstance()->endLearning(); 74 | return SortedIndex; 75 | } 76 | 77 | arma::mat ProbabilisticModel::createFeatureVector(DDElementVector &Source, 78 | DDElementVector &Chunk) { 79 | if (Chunk.size() == 0) 80 | return arma::ones(Source.size(), 1); 81 | 82 | arma::mat Result(Source.size(), 1, arma::fill::zeros); 83 | for (auto C : Chunk) { 84 | if (C.isNull()) 85 | continue; 86 | auto It = std::find(Source.begin(), Source.end(), C); 87 | if (It != std::end(Source)) { 88 | int Index = std::distance(Source.begin(), It); 89 | Result(Index, 0) = 1; 90 | } 91 | } 92 | return Result; 93 | } 94 | -------------------------------------------------------------------------------- /src/core/Reduction.cpp: -------------------------------------------------------------------------------- 1 | #include "Reduction.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "clang/Basic/SourceManager.h" 7 | #include "llvm/Support/Program.h" 8 | 9 | #include "OptionManager.h" 10 | #include "Profiler.h" 11 | 12 | void Reduction::Initialize(clang::ASTContext &C) { 13 | Transformation::Initialize(C); 14 | } 15 | 16 | bool Reduction::callOracle() { 17 | Profiler::GetInstance()->beginOracle(); 18 | int Status = llvm::sys::ExecuteAndWait(OptionManager::OracleFile, 19 | {OptionManager::OracleFile}); 20 | Profiler::GetInstance()->endOracle(); 21 | return (Status == 0); 22 | } 23 | 24 | DDElementSet Reduction::toSet(DDElementVector &Vec) { 25 | DDElementSet S(Vec.begin(), Vec.end()); 26 | return S; 27 | } 28 | 29 | DDElementSet Reduction::setDifference(DDElementSet &A, DDElementSet &B) { 30 | DDElementSet Result; 31 | std::set_difference(A.begin(), A.end(), B.begin(), B.end(), 32 | std::inserter(Result, Result.begin())); 33 | return Result; 34 | } 35 | 36 | DDElementVector Reduction::toVector(DDElementSet &Set) { 37 | DDElementVector Vec(Set.begin(), Set.end()); 38 | return Vec; 39 | } 40 | 41 | std::vector Reduction::getCandidates(DDElementVector &Decls, 42 | int ChunkSize) { 43 | if (Decls.size() == 1) 44 | return {Decls}; 45 | std::vector Result; 46 | int Partitions = Decls.size() / ChunkSize; 47 | for (int Idx = 0; Idx < Partitions; Idx++) { 48 | DDElementVector Target; 49 | Target.insert(Target.end(), Decls.begin() + Idx * ChunkSize, 50 | Decls.begin() + (Idx + 1) * ChunkSize); 51 | if (Target.size() > 0) 52 | Result.emplace_back(Target); 53 | } 54 | for (int Idx = 0; Idx < Partitions; Idx++) { 55 | DDElementVector Complement; 56 | Complement.insert(Complement.end(), Decls.begin(), 57 | Decls.begin() + Idx * ChunkSize); 58 | Complement.insert(Complement.end(), Decls.begin() + (Idx + 1) * ChunkSize, 59 | Decls.end()); 60 | if (Complement.size() > 0) 61 | Result.emplace_back(Complement); 62 | } 63 | 64 | if (OptionManager::SkipLearning) 65 | return Result; 66 | else { 67 | arma::uvec ChunkOrder = TheModel.sortCandidates(Decls, Result); 68 | std::vector SortedResult; 69 | for (int I = 0; I < Result.size(); I++) 70 | if (ChunkOrder[I] != -1) 71 | SortedResult.emplace_back(Result[ChunkOrder[I]]); 72 | return SortedResult; 73 | } 74 | } 75 | 76 | DDElementSet Reduction::doDeltaDebugging(DDElementVector &Decls) { 77 | Cache.clear(); 78 | DDElementSet Removed; 79 | DDElementVector DeclsCopy = Decls; 80 | 81 | TheModel.initialize(Decls); 82 | 83 | int ChunkSize = (DeclsCopy.size() + 1) / 2; 84 | int Iteration = 0; 85 | spdlog::get("Logger")->info("Running delta debugging - Size: {}", 86 | DeclsCopy.size()); 87 | 88 | while (DeclsCopy.size() > 0) { 89 | bool Success = false; 90 | TheModel.train(Iteration); 91 | auto Targets = getCandidates(DeclsCopy, ChunkSize); 92 | for (auto Target : Targets) { 93 | Iteration++; 94 | if (std::find(Cache.begin(), Cache.end(), Target) != Cache.end() || 95 | isInvalidChunk(Target)) 96 | continue; 97 | 98 | if (!OptionManager::NoCache) 99 | Cache.insert(Target); 100 | 101 | bool Status = test(Target); 102 | TheModel.addForTraining(Decls, Target, Status); 103 | if (Status) { 104 | auto TargetSet = toSet(Target); 105 | Removed.insert(TargetSet.begin(), TargetSet.end()); 106 | for (auto T : Target) 107 | DeclsCopy.erase(std::remove(DeclsCopy.begin(), DeclsCopy.end(), T), 108 | DeclsCopy.end()); 109 | Success = true; 110 | break; 111 | } 112 | } 113 | if (Success) { 114 | spdlog::get("Logger")->info("Reduced - Size: {}", DeclsCopy.size()); 115 | ChunkSize = (DeclsCopy.size() + 1) / 2; 116 | } else { 117 | if (ChunkSize == 1) 118 | break; 119 | ChunkSize = (ChunkSize + 1) / 2; 120 | } 121 | } 122 | return Removed; 123 | } 124 | -------------------------------------------------------------------------------- /src/core/Reformat.cpp: -------------------------------------------------------------------------------- 1 | #include "Reformat.h" 2 | 3 | #include "clang/Format/Format.h" 4 | #include "clang/Tooling/Inclusions/HeaderIncludes.h" 5 | 6 | #include "OptionManager.h" 7 | 8 | void Reformat::Initialize(clang::ASTContext &Ctx) { 9 | Transformation::Initialize(Ctx); 10 | } 11 | 12 | std::vector 13 | Reformat::createRanges(llvm::MemoryBuffer *Code) { 14 | llvm::IntrusiveRefCntPtr InMemoryFileSystem( 15 | new llvm::vfs::InMemoryFileSystem); 16 | clang::FileManager Files(clang::FileSystemOptions(), InMemoryFileSystem); 17 | clang::SourceManager *SM = &Context->getSourceManager(); 18 | InMemoryFileSystem.get()->addFileNoOwn("temp", 0, Code); 19 | clang::FileID ID = SM->createFileID( 20 | Files.getFile("temp"), clang::SourceLocation(), clang::SrcMgr::C_User); 21 | 22 | unsigned Offset = SM->getFileOffset(SM->getLocForStartOfFile(ID)); 23 | unsigned Length = SM->getFileOffset(SM->getLocForEndOfFile(ID)) - Offset; 24 | return {clang::tooling::Range(Offset, Length)}; 25 | } 26 | 27 | void Reformat::doReformatting(std::string FileName, 28 | clang::format::FormatStyle FS) { 29 | std::unique_ptr Code = 30 | std::move(llvm::MemoryBuffer::getFile(FileName).get()); 31 | clang::tooling::Replacements Rs = 32 | reformat(FS, Code->getBuffer(), createRanges(Code.get()), FileName); 33 | clang::tooling::applyAllReplacements(Rs, TheRewriter); 34 | TheRewriter.overwriteChangedFiles(); 35 | } 36 | 37 | void Reformat::HandleTranslationUnit(clang::ASTContext &Ctx) { 38 | doReformatting(OptionManager::InputFile, clang::format::getLLVMStyle()); 39 | } 40 | -------------------------------------------------------------------------------- /src/core/SourceManager.cpp: -------------------------------------------------------------------------------- 1 | #include "SourceManager.h" 2 | 3 | #include "clang/Lex/Lexer.h" 4 | 5 | bool SourceManager::IsInHeader(const clang::SourceManager &SM, clang::Decl *D) { 6 | return SM.getFilename(D->getLocation()).endswith(".h"); 7 | } 8 | 9 | clang::SourceLocation 10 | SourceManager::FindLocationAfterCond(const clang::SourceManager &SM, 11 | clang::Expr *E) { 12 | clang::SourceLocation L = E->getEndLoc(); 13 | if (L.isMacroID()) 14 | L = SM.getFileLoc(L); 15 | L = clang::Lexer::findLocationAfterToken(L, clang::tok::r_paren, SM, 16 | clang::LangOptions(), false); 17 | if (L.isMacroID()) 18 | L = SM.getFileLoc(L); 19 | return L; 20 | } 21 | 22 | clang::SourceLocation 23 | SourceManager::GetEndOfCond(const clang::SourceManager &SM, clang::Expr *E) { 24 | clang::SourceLocation L = FindLocationAfterCond(SM, E); 25 | if (L.isInvalid()) 26 | return L; 27 | else 28 | return L.getLocWithOffset(-1); 29 | } 30 | 31 | int getOffsetUntil(const char *Buf, char Symbol) { 32 | int Offset = 0; 33 | while (*Buf != Symbol) { 34 | Buf++; 35 | if (*Buf == '\0') 36 | break; 37 | Offset++; 38 | } 39 | return Offset; 40 | } 41 | 42 | int SourceManager::GetStartingColumn(clang::SourceManager &SM, int Line) { 43 | clang::SourceLocation B = SM.translateLineCol(SM.getMainFileID(), Line, 1); 44 | return clang::Lexer::getIndentationForLine(B, SM).size() + 1; 45 | } 46 | 47 | clang::SourceLocation 48 | SourceManager::GetEndLocationUntil(const clang::SourceManager &SM, 49 | clang::SourceLocation EndLoc, 50 | clang::tok::TokenKind Symbol) { 51 | if (EndLoc.isMacroID()) 52 | EndLoc = SM.getFileLoc(EndLoc); 53 | 54 | if (EndLoc.isInvalid()) 55 | return EndLoc; 56 | 57 | EndLoc = clang::Lexer::findLocationAfterToken(EndLoc, Symbol, SM, 58 | clang::LangOptions(), false); 59 | 60 | if (EndLoc.isMacroID()) 61 | EndLoc = SM.getFileLoc(EndLoc); 62 | 63 | if (EndLoc.isInvalid()) 64 | return EndLoc; 65 | 66 | return EndLoc.getLocWithOffset(-1); 67 | } 68 | 69 | clang::SourceLocation SourceManager::GetEndLocation(clang::ASTContext *Context, 70 | clang::SourceLocation Loc) { 71 | const clang::SourceManager &SM = Context->getSourceManager(); 72 | clang::Token Tok; 73 | 74 | clang::SourceLocation Beginning = 75 | clang::Lexer::GetBeginningOfToken(Loc, SM, Context->getLangOpts()); 76 | clang::Lexer::getRawToken(Beginning, Tok, SM, Context->getLangOpts()); 77 | 78 | clang::SourceLocation End; 79 | if (Tok.getKind() == clang::tok::semi || 80 | Tok.getKind() == clang::tok::r_brace) { 81 | End = Loc; 82 | } else { 83 | End = GetEndLocationUntil(SM, Loc, clang::tok::semi); 84 | } 85 | return End; 86 | } 87 | 88 | clang::SourceLocation 89 | SourceManager::GetRealLocation(clang::ASTContext *Context, 90 | clang::SourceLocation Loc) { 91 | const clang::SourceManager &SM = Context->getSourceManager(); 92 | if (Loc.isMacroID()) 93 | return SM.getFileLoc(Loc); 94 | else 95 | return Loc; 96 | } 97 | 98 | clang::SourceLocation SourceManager::GetBeginOfStmt(clang::ASTContext *Context, 99 | clang::Stmt *S) { 100 | const clang::SourceManager &SM = Context->getSourceManager(); 101 | clang::SourceLocation Start = S->getSourceRange().getBegin(); 102 | if (Start.isMacroID()) 103 | return SM.getFileLoc(Start); 104 | else 105 | return Start; 106 | } 107 | 108 | clang::SourceLocation SourceManager::GetEndOfStmt(clang::ASTContext *Context, 109 | clang::Stmt *S) { 110 | const clang::SourceManager &SM = Context->getSourceManager(); 111 | if (clang::NullStmt *NS = llvm::dyn_cast(S)) 112 | return NS->getSemiLoc(); 113 | if (clang::CompoundStmt *CS = llvm::dyn_cast(S)) 114 | return CS->getRBracLoc(); 115 | if (clang::IfStmt *IS = llvm::dyn_cast(S)) 116 | return GetEndLocation(Context, IS->getEndLoc()); 117 | if (clang::WhileStmt *WS = llvm::dyn_cast(S)) 118 | return GetEndOfStmt(Context, WS->getBody()); 119 | if (clang::DoStmt *DS = llvm::dyn_cast(S)) 120 | return GetEndLocationUntil(SM, DS->getRParenLoc(), clang::tok::semi); 121 | if (clang::ForStmt *FS = llvm::dyn_cast(S)) 122 | return GetEndOfStmt(Context, FS->getBody()); 123 | if (clang::SwitchStmt *SS = llvm::dyn_cast(S)) 124 | return GetEndOfStmt(Context, SS->getBody()); 125 | if (clang::BinaryOperator *BO = llvm::dyn_cast(S)) 126 | return GetEndLocationUntil(SM, BO->getEndLoc(), clang::tok::semi); 127 | if (clang::ReturnStmt *RS = llvm::dyn_cast(S)) 128 | return GetEndLocationUntil(SM, RS->getEndLoc(), clang::tok::semi); 129 | if (clang::GotoStmt *GS = llvm::dyn_cast(S)) 130 | return GetEndLocationUntil(SM, GS->getEndLoc(), clang::tok::semi); 131 | if (clang::BreakStmt *BS = llvm::dyn_cast(S)) 132 | return GetEndLocationUntil(SM, BS->getEndLoc(), clang::tok::semi); 133 | if (clang::ContinueStmt *CS = llvm::dyn_cast(S)) 134 | return GetEndLocationUntil(SM, CS->getEndLoc(), clang::tok::semi); 135 | if (clang::DeclStmt *DS = llvm::dyn_cast(S)) 136 | return DS->getEndLoc(); 137 | if (clang::CallExpr *CE = llvm::dyn_cast(S)) 138 | return GetEndLocationUntil(SM, CE->getEndLoc(), clang::tok::semi); 139 | if (clang::UnaryOperator *UO = llvm::dyn_cast(S)) 140 | return GetEndLocationUntil(SM, UO->getEndLoc(), clang::tok::semi); 141 | if (clang::LabelStmt *LS = llvm::dyn_cast(S)) 142 | return GetEndOfStmt(Context, LS->getSubStmt()); 143 | if (clang::ParenExpr *PE = llvm::dyn_cast(S)) 144 | return GetEndLocationUntil(SM, PE->getEndLoc(), clang::tok::semi); 145 | if (clang::SwitchCase *SC = llvm::dyn_cast(S)) 146 | return GetEndLocationUntil(SM, SC->getEndLoc(), clang::tok::semi); 147 | if (clang::CastExpr *CE = llvm::dyn_cast(S)) 148 | return GetEndOfStmt(Context, CE->getSubExpr()); 149 | if (clang::GCCAsmStmt *AS = llvm::dyn_cast(S)) 150 | return GetEndLocationUntil(SM, AS->getEndLoc(), clang::tok::semi); 151 | 152 | return S->getEndLoc(); 153 | } 154 | 155 | llvm::StringRef SourceManager::GetSourceText(const clang::SourceManager &SM, 156 | const clang::SourceLocation &B, 157 | const clang::SourceLocation &E) { 158 | return clang::Lexer::getSourceText( 159 | clang::CharSourceRange::getCharRange(B, E.getLocWithOffset(1)), SM, 160 | clang::LangOptions()); 161 | } 162 | 163 | llvm::StringRef SourceManager::GetSourceText(const clang::SourceManager &SM, 164 | const clang::SourceRange &SR) { 165 | return GetSourceText(SM, SR.getBegin(), SR.getEnd()); 166 | } 167 | -------------------------------------------------------------------------------- /src/core/Transformation.cpp: -------------------------------------------------------------------------------- 1 | #include "Transformation.h" 2 | 3 | #include "SourceManager.h" 4 | 5 | #include "OptionManager.h" 6 | 7 | #include "Profiler.h" 8 | 9 | #include 10 | 11 | #include "llvm/Support/Program.h" 12 | 13 | #include "clang/Lex/Lexer.h" 14 | 15 | #include 16 | 17 | void Transformation::Initialize(clang::ASTContext &C) { 18 | Context = &C; 19 | TheRewriter.setSourceMgr(Context->getSourceManager(), Context->getLangOpts()); 20 | } 21 | 22 | std::vector Transformation::getAllChildren(clang::Stmt *S) { 23 | std::queue ToVisit; 24 | std::vector AllChildren; 25 | ToVisit.push(S); 26 | while (!ToVisit.empty()) { 27 | auto C = ToVisit.front(); 28 | ToVisit.pop(); 29 | AllChildren.emplace_back(C); 30 | for (auto const &Child : C->children()) { 31 | if (Child != NULL) 32 | ToVisit.push(Child); 33 | } 34 | } 35 | return AllChildren; 36 | } 37 | 38 | void Transformation::removeSourceText(const clang::SourceLocation &B, 39 | const clang::SourceLocation &E) { 40 | llvm::StringRef Text = 41 | SourceManager::GetSourceText(Context->getSourceManager(), B, E); 42 | std::string Replacement = ""; 43 | for (auto const &chr : Text) { 44 | if (chr == '\n') 45 | Replacement += '\n'; 46 | else if (isprint(chr) || !isascii(chr)) 47 | Replacement += " "; 48 | else 49 | Replacement += chr; 50 | } 51 | TheRewriter.ReplaceText(clang::SourceRange(B, E), Replacement); 52 | } 53 | 54 | bool Transformation::callOracle() { 55 | Profiler::GetInstance()->beginOracle(); 56 | int Status = llvm::sys::ExecuteAndWait(OptionManager::OracleFile, 57 | {OptionManager::OracleFile}); 58 | Profiler::GetInstance()->endOracle(); 59 | return (Status == 0); 60 | } 61 | 62 | void Transformation::revertRemoval(const std::vector &Ranges, const std::vector &Reverts){ 63 | for (int i = 0; i < Reverts.size(); i++) 64 | TheRewriter.ReplaceText(Ranges[i], Reverts[i]); 65 | TheRewriter.overwriteChangedFiles(); 66 | return ; 67 | } -------------------------------------------------------------------------------- /src/utils/FileManager.cpp: -------------------------------------------------------------------------------- 1 | #include "FileManager.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "llvm/Support/FileSystem.h" 7 | 8 | #include "OptionManager.h" 9 | 10 | FileManager *FileManager::Instance; 11 | 12 | void FileManager::Initialize() { 13 | Instance = new FileManager(); 14 | llvm::sys::fs::create_directory(OptionManager::OutputDir); 15 | } 16 | 17 | FileManager *FileManager::GetInstance() { 18 | if (!Instance) 19 | Initialize(); 20 | return Instance; 21 | } 22 | 23 | std::string FileManager::getTempFileName(std::string Suffix) { 24 | std::string Name = OptionManager::OutputDir + "/" + 25 | Basename(OptionManager::InputFile) + "." + 26 | std::to_string(TempCounter) + "." + Suffix; 27 | TempCounter++; 28 | return Name; 29 | } 30 | 31 | void FileManager::saveTemp(std::string Phase, bool Status) { 32 | if (OptionManager::SaveTemp) { 33 | std::string StatusString = Status ? ".success.c" : ".fail.c"; 34 | llvm::sys::fs::copy_file(OptionManager::InputFile, 35 | getTempFileName(Phase) + StatusString); 36 | } 37 | } 38 | 39 | std::string FileManager::Readlink(std::string &Name) { 40 | std::string buffer(64, '\0'); 41 | ssize_t len; 42 | while ((len = ::readlink(Name.c_str(), &buffer[0], buffer.size())) == 43 | static_cast(buffer.size())) { 44 | buffer.resize(buffer.size() * 2); 45 | } 46 | if (len == -1) { 47 | return Name; 48 | } 49 | buffer.resize(len); 50 | return buffer; 51 | } 52 | 53 | std::string FileManager::Dirname(std::string &Name) { 54 | char *Cstr = new char[Name.length() + 1]; 55 | strcpy(Cstr, Name.c_str()); 56 | ::dirname(Cstr); 57 | std::string Dir(Cstr); 58 | delete[] Cstr; 59 | return Dir; 60 | } 61 | 62 | std::string FileManager::Basename(std::string &Name) { 63 | int Idx = Name.rfind('/', Name.length()); 64 | if (Idx != std::string::npos) { 65 | return (Name.substr(Idx + 1, Name.length() - Idx)); 66 | } 67 | return Name; 68 | } 69 | 70 | void FileManager::Finalize() { 71 | delete Instance; 72 | } 73 | -------------------------------------------------------------------------------- /src/utils/IntegrationManager.cpp: -------------------------------------------------------------------------------- 1 | #include "IntegrationManager.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include "llvm/ADT/APInt.h" 12 | #include "llvm/Support/FileSystem.h" 13 | #include "llvm/Support/Process.h" 14 | #include "llvm/Support/Program.h" 15 | #include "llvm/Support/raw_ostream.h" 16 | 17 | #include "FileManager.h" 18 | #include "OptionManager.h" 19 | 20 | IntegrationManager *IntegrationManager::Instance; 21 | 22 | std::vector getAllEnv() { 23 | std::vector Env; 24 | for (char **p = environ; *p != 0; p++) 25 | Env.push_back(*p); 26 | return Env; 27 | } 28 | 29 | std::vector stringToVector(std::string &Str, char dilim) { 30 | std::vector Vec; 31 | std::stringstream SS(Str); 32 | std::string Token; 33 | while (getline(SS, Token, dilim)) 34 | Vec.push_back(Token); 35 | return Vec; 36 | } 37 | 38 | bool endsWith(const std::string &Main, const std::string &Match) { 39 | if (Main.size() >= Match.size() && 40 | Main.compare(Main.size() - Match.size(), Match.size(), Match) == 0) 41 | return true; 42 | else 43 | return false; 44 | } 45 | 46 | void clean(std::string &Program) { 47 | if (endsWith(Program, "make")) { 48 | std::vector Args; 49 | Args.push_back("make"); 50 | Args.push_back("clean"); 51 | llvm::sys::ExecuteAndWait(Program, Args, llvm::None, {}, 0, 0, nullptr); 52 | } 53 | } 54 | 55 | // Run build commands and capture compile options 56 | void IntegrationManager::capture() { 57 | llvm::Optional OldPathOpt = llvm::sys::Process::GetEnv("PATH"); 58 | std::string OldPath; 59 | if (OldPathOpt.hasValue()) 60 | OldPath = OldPathOpt.getValue(); 61 | else 62 | OldPath = ""; 63 | std::string ExtendedPath = WrapperDir + ":" + OldPath; 64 | 65 | std::string ChiselOldPath = "CHISEL_OLD_PATH=" + OldPath; 66 | std::string Path = "PATH=" + ExtendedPath; 67 | std::string ChiselOutputDir = "CHISEL_OUTPUT_DIR=" + OptionManager::OutputDir; 68 | 69 | std::vector Env = getAllEnv(); 70 | Env.push_back(ChiselOldPath); 71 | Env.push_back(Path); 72 | Env.push_back(ChiselOutputDir); 73 | 74 | std::vector Args; 75 | for (auto &Arg : OptionManager::BuildCmd) 76 | Args.push_back(Arg); 77 | 78 | std::vector PathVec = stringToVector(ExtendedPath, ':'); 79 | std::vector PathVecRef; 80 | for (auto &Path : PathVec) 81 | PathVecRef.push_back(Path); 82 | 83 | llvm::ErrorOr Program = llvm::sys::findProgramByName( 84 | OptionManager::BuildCmd[0], llvm::ArrayRef(PathVecRef)); 85 | if (Program) { 86 | // Clean up the repository (e.g., make clean). Delete files that were 87 | // generated by the initial running of the test script in OptionManager 88 | clean(Program.get()); 89 | std::string Msg; 90 | int Status = llvm::sys::ExecuteAndWait( 91 | Program.get(), Args, 92 | llvm::Optional>(Env), {}, 0, 0, &Msg); 93 | if (Status) { 94 | llvm::errs() << "Error: Capture failed: " << Msg << "\n"; 95 | exit(1); 96 | } 97 | } else { 98 | llvm::errs() << "Error: Unsupported build system " 99 | << OptionManager::BuildCmd[0] << "\n"; 100 | exit(1); 101 | } 102 | } 103 | 104 | void IntegrationManager::buildCompilationDB() { 105 | std::string Line; 106 | std::ifstream CaptureFile(CaptureFilePath); 107 | if (!CaptureFile.is_open()) { 108 | llvm::errs() << "Error: Unable to open capture.txt\n"; 109 | exit(1); 110 | } 111 | 112 | while (getline(CaptureFile, Line)) { 113 | std::stringstream SS(Line); 114 | std::string Token; 115 | int i = 0; 116 | std::string SourceFile; 117 | std::vector Args; 118 | while (getline(SS, Token, ',')) { 119 | // the first token means compiler 120 | if (i > 0) { 121 | if (endsWith(Token, ".c")) 122 | SourceFile = Token; 123 | else 124 | Args.push_back(Token); 125 | } 126 | i++; 127 | } 128 | if (!SourceFile.empty()) 129 | CompilationDB[SourceFile] = Args; 130 | } 131 | CaptureFile.close(); 132 | 133 | for (auto &E : CompilationDB) 134 | OptionManager::InputFiles.push_back(E.first); 135 | } 136 | 137 | void IntegrationManager::Initialize() { 138 | Instance = new IntegrationManager(); 139 | Instance->CaptureFilePath = OptionManager::OutputDir + "/capture.txt"; 140 | Instance->WrapperDir = 141 | FileManager::Dirname(OptionManager::BinFile) + "/../lib/wrappers"; 142 | spdlog::get("Logger")->debug("Wrapper Directory: {}", Instance->WrapperDir); 143 | if (OptionManager::Build) { 144 | llvm::sys::fs::remove(Instance->CaptureFilePath); 145 | Instance->capture(); 146 | Instance->buildCompilationDB(); 147 | } 148 | for (auto &File : OptionManager::InputFiles) { 149 | std::string Origin = File + ".origin.c"; 150 | Instance->Origins.push_back(Origin); 151 | llvm::sys::fs::copy_file(File, Origin); 152 | } 153 | } 154 | 155 | std::vector 156 | IntegrationManager::getCC1Args(std::string &FileName) { 157 | std::vector Args; 158 | bool Record = false; 159 | for (auto &Arg : CompilationDB[FileName]) { 160 | if (Arg.find("-I") == 0 || Arg.find("-D") == 0) { 161 | Args.push_back(Arg.c_str()); 162 | Record = true; 163 | } else if (Arg.find("-") == 0) { 164 | Record = false; 165 | } else if (Record) { 166 | Args.push_back(Arg.c_str()); 167 | } else if (endsWith(Arg, ".o")) { 168 | Record = false; 169 | } 170 | } 171 | return Args; 172 | } 173 | 174 | void IntegrationManager::Finalize() { 175 | for (auto &File : OptionManager::InputFiles) { 176 | std::string Origin = File + ".origin.c"; 177 | llvm::sys::fs::copy_file(File, File + ".chisel.c"); 178 | llvm::sys::fs::copy_file(Origin, File); 179 | } 180 | delete Instance; 181 | } 182 | -------------------------------------------------------------------------------- /src/utils/OptionManager.cpp: -------------------------------------------------------------------------------- 1 | #include "OptionManager.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "llvm/Support/FileSystem.h" 7 | #include "llvm/Support/Program.h" 8 | #include "llvm/Support/raw_ostream.h" 9 | 10 | #include "FileManager.h" 11 | 12 | const std::string usage_simple("Usage: chisel [OPTIONS]... ORACLE PROGRAM"); 13 | const std::string error_message("Try 'chisel --help' for more information."); 14 | 15 | void OptionManager::showUsage() { 16 | llvm::errs() 17 | << usage_simple << "\n" 18 | << "Options:" 19 | << "\n" 20 | << " --help Show this help message\n" 21 | << " --output_dir OUTDIR Output directory\n" 22 | << " --build Integrate Chisel with build system\n" 23 | << " --save_temp Save intermediate results\n" 24 | << " --skip_learning Disable decision tree learning\n" 25 | << " --skip_delay_learning Learn a new model for every iteration\n" 26 | << " --skip_global Skip global-level reduction\n" 27 | << " --skip_local Skip function-level reduction\n" 28 | << " --no_cache Do not cache intermediate results\n" 29 | << " --skip_local_dep Disable local dependency checking\n" 30 | << " --skip_global_dep Disable global dependency checking\n" 31 | << " --skip_dce Do not perform static unreachability " 32 | "analysis\n" 33 | << " --no_profile Do not print profiling report\n" 34 | << " --debug Print debug information\n" 35 | << " --stat Count the number of statements\n" 36 | << " --xref Visualize the results only\n"; 37 | } 38 | 39 | static struct option long_options[] = { 40 | {"help", no_argument, 0, 'h'}, 41 | {"output_dir", required_argument, 0, 't'}, 42 | {"build", no_argument, 0, 'b'}, 43 | {"save_temp", no_argument, 0, 's'}, 44 | {"skip_learning", no_argument, 0, 'D'}, 45 | {"skip_delay_learning", no_argument, 0, 'd'}, 46 | {"skip_global", no_argument, 0, 'g'}, 47 | {"skip_local", no_argument, 0, 'l'}, 48 | {"no_cache", no_argument, 0, 'c'}, 49 | {"skip_local_dep", no_argument, 0, 'L'}, 50 | {"skip_global_dep", no_argument, 0, 'G'}, 51 | {"skip_dce", no_argument, 0, 'C'}, 52 | {"no_profile", no_argument, 0, 'p'}, 53 | {"debug", no_argument, 0, 'v'}, 54 | {"stat", no_argument, 0, 'S'}, 55 | {"xref", no_argument, 0, 'X'}, 56 | {0, 0, 0, 0}}; 57 | 58 | static const char *optstring = "ho:t:sDdglcLGCpvSX"; 59 | 60 | std::string OptionManager::BinFile = ""; 61 | std::vector OptionManager::InputFiles; 62 | std::vector OptionManager::BuildCmd; 63 | std::string OptionManager::InputFile = ""; 64 | std::string OptionManager::OracleFile = ""; 65 | std::string OptionManager::OutputDir = "chisel-out"; 66 | bool OptionManager::Build = false; 67 | bool OptionManager::SaveTemp = false; 68 | bool OptionManager::SkipLearning = false; 69 | bool OptionManager::SkipDelayLearning = false; 70 | bool OptionManager::SkipGlobal = false; 71 | bool OptionManager::SkipLocal = false; 72 | bool OptionManager::NoCache = false; 73 | bool OptionManager::SkipGlobalDep = false; 74 | bool OptionManager::SkipLocalDep = false; 75 | bool OptionManager::SkipDCE = false; 76 | bool OptionManager::Profile = true; 77 | bool OptionManager::Debug = false; 78 | bool OptionManager::Stat = false; 79 | bool OptionManager::XRef = false; 80 | 81 | void OptionManager::handleOptions(int argc, char *argv[]) { 82 | llvm::ErrorOr Program = llvm::sys::findProgramByName(argv[0]); 83 | BinFile = FileManager::Readlink(Program.get()); 84 | 85 | char c; 86 | while ((c = getopt_long(argc, argv, optstring, long_options, 0)) != -1) { 87 | switch (c) { 88 | case 'h': 89 | showUsage(); 90 | exit(0); 91 | 92 | case 't': 93 | OptionManager::OutputDir = std::string(optarg); 94 | break; 95 | 96 | case 'b': 97 | Build = true; 98 | break; 99 | 100 | case 's': 101 | OptionManager::SaveTemp = true; 102 | break; 103 | 104 | case 'D': 105 | OptionManager::SkipLearning = true; 106 | break; 107 | 108 | case 'd': 109 | OptionManager::SkipDelayLearning = true; 110 | break; 111 | 112 | case 'g': 113 | OptionManager::SkipGlobal = true; 114 | break; 115 | 116 | case 'l': 117 | OptionManager::SkipLocal = true; 118 | break; 119 | 120 | case 'c': 121 | OptionManager::NoCache = true; 122 | break; 123 | 124 | case 'L': 125 | OptionManager::SkipLocalDep = true; 126 | break; 127 | 128 | case 'G': 129 | OptionManager::SkipGlobalDep = true; 130 | break; 131 | 132 | case 'C': 133 | OptionManager::SkipDCE = true; 134 | break; 135 | 136 | case 'p': 137 | OptionManager::Profile = false; 138 | break; 139 | 140 | case 'v': 141 | OptionManager::Debug = true; 142 | break; 143 | 144 | case 'S': 145 | OptionManager::Stat = true; 146 | break; 147 | 148 | case 'X': 149 | OptionManager::XRef = true; 150 | break; 151 | 152 | default: 153 | llvm::errs() << "Invalid option.\n"; 154 | llvm::errs() << usage_simple << "\n"; 155 | llvm::errs() << error_message << "\n"; 156 | exit(1); 157 | } 158 | } 159 | 160 | if (optind + 2 > argc && !OptionManager::Stat) { 161 | llvm::errs() << "chisel: You must specify the oracle and input.\n"; 162 | llvm::errs() << usage_simple << "\n"; 163 | llvm::errs() << error_message << "\n"; 164 | exit(1); 165 | } else if (optind + 1 > argc && OptionManager::Stat) { 166 | llvm::errs() << "chisel: You must specify the input.\n"; 167 | exit(1); 168 | } 169 | 170 | int i; 171 | if (Stat) 172 | i = optind; 173 | else 174 | i = optind + 1; 175 | 176 | if (Build) { 177 | // integrate Chisel with build system 178 | // input files will be captured by IntegrationManager 179 | for (; i < argc; i++) 180 | BuildCmd.push_back(std::string(argv[i])); 181 | } else { 182 | for (; i < argc; i++) { 183 | std::string Input = std::string(argv[i]); 184 | if (!llvm::sys::fs::exists(Input)) { 185 | llvm::errs() << "The specified input file " << Input 186 | << " does not exist.\n"; 187 | exit(1); 188 | } 189 | InputFiles.push_back(Input); 190 | } 191 | } 192 | 193 | // When Chisel only computes statistics, it does not need to check the oracle 194 | if (OptionManager::Stat) 195 | return; 196 | 197 | OptionManager::OracleFile = std::string(argv[optind]); 198 | 199 | if (!llvm::sys::fs::exists(OptionManager::OracleFile)) { 200 | llvm::errs() << "The specified oracle file " << OptionManager::OracleFile 201 | << " does not exist.\n"; 202 | exit(1); 203 | } else if (!llvm::sys::fs::can_execute(OptionManager::OracleFile)) { 204 | llvm::errs() << "The specified oracle file " << OptionManager::OracleFile 205 | << " is not executable.\n"; 206 | exit(1); 207 | } else if (llvm::sys::ExecuteAndWait(OptionManager::OracleFile, 208 | {OptionManager::OracleFile})) { 209 | llvm::errs() << "The specified oracle file " << OptionManager::OracleFile 210 | << " cannot execute correctly.\n"; 211 | exit(1); 212 | } 213 | 214 | llvm::SmallString<128> OutputDirVec(OutputDir); 215 | llvm::sys::fs::make_absolute(OutputDirVec); 216 | OutputDir = OutputDirVec.str(); 217 | } 218 | -------------------------------------------------------------------------------- /src/utils/Profiler.cpp: -------------------------------------------------------------------------------- 1 | #include "Profiler.h" 2 | 3 | #include "llvm/Support/Timer.h" 4 | 5 | Profiler *Profiler::Instance; 6 | 7 | void Profiler::Initialize() { 8 | Instance = new Profiler(); 9 | 10 | Instance->ChiselTimer.init("ChiselTimer", ""); 11 | Instance->OracleTimer.init("OracleTimer", ""); 12 | Instance->LearningTimer.init("LearningTimer", ""); 13 | } 14 | 15 | Profiler *Profiler::GetInstance() { 16 | if (!Instance) 17 | Initialize(); 18 | return Instance; 19 | } 20 | 21 | void Profiler::Finalize() { delete Instance; } 22 | 23 | void Profiler::incrementGlobalReductionCounter() { GlobalReductionCounter++; } 24 | 25 | void Profiler::incrementSuccessfulGlobalReductionCounter() { 26 | SuccessfulGlobalReductionCounter++; 27 | } 28 | 29 | void Profiler::incrementLocalReductionCounter() { LocalReductionCounter++; } 30 | 31 | void Profiler::incrementSuccessfulLocalReductionCounter() { 32 | SuccessfulLocalReductionCounter++; 33 | } 34 | 35 | void Profiler::beginChisel() { 36 | assert(ChiselTimer.isInitialized()); 37 | ChiselTimer.startTimer(); 38 | } 39 | 40 | void Profiler::endChisel() { 41 | assert(ChiselTimer.isRunning()); 42 | ChiselTimer.stopTimer(); 43 | ChiselTimeRecord += ChiselTimer.getTotalTime(); 44 | ChiselTimer.clear(); 45 | } 46 | 47 | void Profiler::beginOracle() { 48 | assert(OracleTimer.isInitialized()); 49 | OracleTimer.startTimer(); 50 | } 51 | 52 | void Profiler::endOracle() { 53 | assert(OracleTimer.isRunning()); 54 | OracleTimer.stopTimer(); 55 | OracleTimeRecord += OracleTimer.getTotalTime(); 56 | OracleTimer.clear(); 57 | } 58 | 59 | void Profiler::beginLearning() { 60 | assert(LearningTimer.isInitialized()); 61 | LearningTimer.startTimer(); 62 | } 63 | 64 | void Profiler::endLearning() { 65 | assert(LearningTimer.isRunning()); 66 | LearningTimer.stopTimer(); 67 | LearningTimeRecord += LearningTimer.getTotalTime(); 68 | LearningTimer.clear(); 69 | } 70 | -------------------------------------------------------------------------------- /src/utils/Report.cpp: -------------------------------------------------------------------------------- 1 | #include "Report.h" 2 | 3 | #include 4 | 5 | #include "llvm/Support/Format.h" 6 | #include "llvm/Support/raw_ostream.h" 7 | 8 | #include "FileManager.h" 9 | #include "IntegrationManager.h" 10 | #include "OptionManager.h" 11 | #include "Profiler.h" 12 | #include "StatsManager.h" 13 | 14 | void Report::print() { 15 | Profiler *Prof = Profiler::GetInstance(); 16 | 17 | int TotalWidth = 52; 18 | int LeftColWidth = 25; 19 | const char *RightColFmt = "%21.1f"; 20 | std::string Bar(TotalWidth, '='); 21 | 22 | spdlog::get("Logger")->info(Bar); 23 | spdlog::get("Logger")->info("{:^52}", "Report"); 24 | spdlog::get("Logger")->info(Bar); 25 | spdlog::get("Logger")->info("{:>25}{:>21.1f}s", "Total Time :", 26 | Prof->getChiselTimeRecord().getWallTime()); 27 | spdlog::get("Logger")->info("{:>25}{:>21.1f}s", "Oracle Time :", 28 | Prof->getOracleTimeRecord().getWallTime()); 29 | if (!OptionManager::SkipLearning) { 30 | spdlog::get("Logger")->info("{:>25}{:>21.1f}s", "Learning Time :", 31 | Prof->getLearningTimeRecord().getWallTime()); 32 | } 33 | if (!OptionManager::SkipGlobal) { 34 | int Ratio = Prof->getGlobalReductionCounter() 35 | ? Prof->getSuccessfulGlobalReductionCounter() * 100 / 36 | Prof->getGlobalReductionCounter() 37 | : 0; 38 | spdlog::get("Logger")->info("{:>25}{:>5}% ({:>5} / {:>5})", 39 | "Global Success Ratio :", Ratio, 40 | Prof->getSuccessfulGlobalReductionCounter(), 41 | Prof->getGlobalReductionCounter()); 42 | } 43 | if (!OptionManager::SkipLocal) { 44 | int Ratio = Prof->getLocalReductionCounter() 45 | ? Prof->getSuccessfulLocalReductionCounter() * 100 / 46 | Prof->getLocalReductionCounter() 47 | : 0; 48 | spdlog::get("Logger")->info("{:>25}{:>5}% ({:>5} / {:>5})", 49 | "Local Success Ratio :", Ratio, 50 | Prof->getSuccessfulLocalReductionCounter(), 51 | Prof->getLocalReductionCounter()); 52 | } 53 | StatsManager::ComputeStats( 54 | IntegrationManager::GetInstance()->getOriginFilePaths()); 55 | spdlog::get("Logger")->info("{:>25}{:>22}", "#Functions (Original) :", 56 | StatsManager::GetNumOfFunctions()); 57 | spdlog::get("Logger")->info("{:>25}{:>22}", "#Statements (Original) :", 58 | StatsManager::GetNumOfStatements()); 59 | StatsManager::ComputeStats(OptionManager::InputFiles); 60 | spdlog::get("Logger")->info("{:>25}{:>22}", "#Functions (Reduced) :", 61 | StatsManager::GetNumOfFunctions()); 62 | spdlog::get("Logger")->info("{:>25}{:>22}", "#Statements (Reduced) :", 63 | StatsManager::GetNumOfStatements()); 64 | } 65 | -------------------------------------------------------------------------------- /src/utils/StatsManager.cpp: -------------------------------------------------------------------------------- 1 | #include "StatsManager.h" 2 | 3 | #include 4 | 5 | #include "clang/AST/Expr.h" 6 | 7 | #include "Frontend.h" 8 | 9 | int StatsManager::NumOfWords = 0; 10 | int StatsManager::NumOfStatements = 0; 11 | int StatsManager::NumOfFunctions = 0; 12 | 13 | void StatsManager::ComputeStats(std::vector &FileNames) { 14 | NumOfWords = 0; 15 | NumOfStatements = 0; 16 | NumOfFunctions = 0; 17 | 18 | for (auto &FileName : FileNames) { 19 | StatsComputer *S = new StatsComputer(); 20 | Frontend::Parse(FileName, S); 21 | 22 | std::ifstream IFS(FileName.c_str()); 23 | std::string Word; 24 | while (IFS >> Word) { 25 | NumOfWords++; 26 | } 27 | } 28 | } 29 | 30 | void StatsManager::ComputeStats(std::string &FileName) { 31 | NumOfWords = 0; 32 | NumOfStatements = 0; 33 | NumOfFunctions = 0; 34 | StatsComputer *S = new StatsComputer(); 35 | Frontend::Parse(FileName, S); 36 | 37 | std::ifstream IFS(FileName.c_str()); 38 | std::string Word; 39 | while (IFS >> Word) { 40 | NumOfWords++; 41 | } 42 | } 43 | 44 | void StatsManager::Print() { 45 | llvm::outs() << "# Functions : " << NumOfFunctions << "\n"; 46 | llvm::outs() << "# Statements : " << NumOfStatements << "\n"; 47 | } 48 | 49 | void StatsManager::IncreaseNumOfFunctions() { NumOfFunctions++; } 50 | 51 | void StatsManager::IncreaseNumOfStatements() { NumOfStatements++; } 52 | 53 | bool StatsManager::isCountableStatement(clang::Stmt *S) { 54 | if (clang::Expr *E = llvm::dyn_cast(S)) { 55 | if (clang::BinaryOperator *BO = llvm::dyn_cast(E)) { 56 | return BO->isAssignmentOp(); 57 | } else if (clang::UnaryOperator *UO = 58 | llvm::dyn_cast(E)) { 59 | return UO->isIncrementDecrementOp(); 60 | } else if (clang::CallExpr *CE = llvm::dyn_cast(E)) { 61 | return true; 62 | } else { 63 | return false; 64 | } 65 | } else if (clang::CompoundStmt *C = llvm::dyn_cast(S)) { 66 | return false; 67 | } else if (clang::NullStmt *N = llvm::dyn_cast(S)) { 68 | return false; 69 | } else if (clang::LabelStmt *L = llvm::dyn_cast(S)) { 70 | return false; 71 | } else if (clang::DeclStmt *D = llvm::dyn_cast(S)) { 72 | if (D->isSingleDecl()) { 73 | if (clang::VarDecl *VD = 74 | llvm::dyn_cast(D->getSingleDecl())) { 75 | return VD->hasInit(); 76 | } 77 | } 78 | return false; 79 | } else if (clang::SwitchCase *SC = llvm::dyn_cast(S)) { 80 | return false; 81 | } else { 82 | return true; 83 | } 84 | } 85 | 86 | void StatsComputer::Initialize(clang::ASTContext &Ctx) { 87 | Visitor = new StatsVisitor(); 88 | } 89 | 90 | bool StatsComputer::HandleTopLevelDecl(clang::DeclGroupRef D) { 91 | for (clang::DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { 92 | Visitor->TraverseDecl(*I); 93 | } 94 | return true; 95 | } 96 | 97 | bool StatsVisitor::VisitFunctionDecl(clang::FunctionDecl *FD) { 98 | if (FD->isThisDeclarationADefinition()) 99 | StatsManager::IncreaseNumOfFunctions(); 100 | return true; 101 | } 102 | 103 | bool StatsVisitor::VisitStmt(clang::Stmt *S) { 104 | if (StatsManager::isCountableStatement(S)) 105 | StatsManager::IncreaseNumOfStatements(); 106 | return true; 107 | } 108 | -------------------------------------------------------------------------------- /src/xref/Visualization.cpp: -------------------------------------------------------------------------------- 1 | #include "Visualization.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "llvm/Support/Process.h" 8 | #include "llvm/Support/Program.h" 9 | 10 | #include "OptionManager.h" 11 | 12 | void Visualization::generate(std::string Filename) { 13 | // Reformat both files 14 | llvm::ErrorOr ClangFormat = 15 | llvm::sys::findProgramByName("clang-format"); 16 | if (ClangFormat) { 17 | std::ofstream ClangConfig(".clang-format"); 18 | ClangConfig 19 | << "AlwaysBreakAfterReturnType: All\nBreakBeforeBraces: Allman\n"; 20 | ClangConfig.close(); 21 | llvm::sys::ExecuteAndWait( 22 | ClangFormat.get(), 23 | {ClangFormat.get(), "-i", Filename, Filename + ".chisel.c"}); 24 | } else 25 | llvm::errs() << "Cannot find clang-format. The visualization result might " 26 | "not be precise.\n"; 27 | 28 | // Call the oracle to record covered lines 29 | int Status = llvm::sys::ExecuteAndWait(OptionManager::OracleFile, 30 | {OptionManager::OracleFile, "1"}); 31 | 32 | // Find and record the common line numbers 33 | std::string Diff = 34 | "diff --unchanged-line-format=$'\%dn\\n' --new-line-format='' " 35 | "--old-line-format='' --ignore-space-change " + 36 | Filename + " " + Filename + ".chisel.c"; 37 | Save(ParseNumbers(getStdoutFromCommand(Diff)), Filename + ".common"); 38 | 39 | // If the Generator exists, generate HTML cross-referencing 40 | llvm::ErrorOr Generator = 41 | llvm::sys::findProgramByName("generator"); 42 | if (Generator) 43 | llvm::sys::ExecuteAndWait(Generator.get(), 44 | {Generator.get(), "-o", "xref-output", "-p", 45 | Filename + ":.", Filename, "--", 46 | "-I/opt/llvm/include"}); 47 | else { 48 | llvm::errs() 49 | << "Cannot find generator. The visualization phase is incomplete.\n"; 50 | return; 51 | } 52 | 53 | // Copy static data for HTML 54 | std::string StaticPath = 55 | Generator.get().substr(0, Generator.get().find_last_of("\\/")) + 56 | "/../../data"; 57 | llvm::sys::ExecuteAndWait("/bin/cp", 58 | {"/bin/cp", "-r", StaticPath, "xref-output/../"}); 59 | } 60 | 61 | void Visualization::Save(std::vector Numbers, 62 | std::string Filename) { 63 | std::ofstream OutputFile(Filename); 64 | for (const auto &N : Numbers) 65 | OutputFile << N << "\n"; 66 | } 67 | 68 | std::vector Visualization::ParseNumbers(std::string String) { 69 | std::istringstream iss(String); 70 | std::string Token; 71 | std::vector Numbers; 72 | 73 | while (std::getline(iss, Token, '$')) { 74 | if (Token.size() <= 2) 75 | continue; 76 | Numbers.emplace_back(Token.substr(0, Token.size() - 2)); 77 | } 78 | return Numbers; 79 | } 80 | 81 | std::string Visualization::getStdoutFromCommand(std::string Command) { 82 | std::string Data; 83 | FILE *Stream; 84 | char Buffer[256]; 85 | Command.append(" 2>&1"); 86 | 87 | Stream = popen(Command.c_str(), "r"); 88 | if (Stream) { 89 | while (!feof(Stream)) 90 | if (fgets(Buffer, sizeof(Buffer), Stream) != NULL) 91 | Data.append(Buffer); 92 | pclose(Stream); 93 | } 94 | return Data; 95 | } 96 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_test( 2 | NAME basic0 3 | COMMAND ./test.sh basic0 basic0.c 4 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 5 | ) 6 | 7 | add_test( 8 | NAME basic1 9 | COMMAND ./test.sh basic1 basic1.c 10 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 11 | ) 12 | 13 | add_test( 14 | NAME basic2 15 | COMMAND ./test.sh basic2 basic2.c 16 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 17 | ) 18 | 19 | add_test( 20 | NAME basic3 21 | COMMAND ./test.sh basic3 basic3.c 22 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 23 | ) 24 | 25 | add_test( 26 | NAME basic4 27 | COMMAND ./test.sh basic4 basic4.c 28 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 29 | ) 30 | 31 | add_test( 32 | NAME basic5 33 | COMMAND ./test.sh basic5 basic5.c 34 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 35 | ) 36 | 37 | add_test( 38 | NAME conditional0 39 | COMMAND ./test.sh conditional0 conditional0.c 40 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 41 | ) 42 | 43 | add_test( 44 | NAME conditional1 45 | COMMAND ./test.sh conditional1 conditional1.c 46 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 47 | ) 48 | 49 | add_test( 50 | NAME conditional2 51 | COMMAND ./test.sh conditional2 conditional2.c 52 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 53 | ) 54 | 55 | add_test( 56 | NAME conditional3 57 | COMMAND ./test.sh conditional3 conditional3.c 58 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 59 | ) 60 | 61 | add_test( 62 | NAME loop0 63 | COMMAND ./test.sh loop0 loop0.c 64 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 65 | ) 66 | 67 | add_test( 68 | NAME loop1 69 | COMMAND ./test.sh loop1 loop1.c 70 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 71 | ) 72 | 73 | add_test( 74 | NAME for0 75 | COMMAND ./test.sh for0 for0.c 76 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 77 | ) 78 | 79 | add_test( 80 | NAME for1 81 | COMMAND ./test.sh for1 for1.c 82 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 83 | ) 84 | 85 | add_test( 86 | NAME for2 87 | COMMAND ./test.sh for2 for2.c 88 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 89 | ) 90 | 91 | add_test( 92 | NAME for3 93 | COMMAND ./test.sh for3 for3.c 94 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 95 | ) 96 | 97 | add_test( 98 | NAME do-while0 99 | COMMAND ./test.sh do-while0 do-while0.c 100 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 101 | ) 102 | 103 | add_test( 104 | NAME do-while1 105 | COMMAND ./test.sh do-while1 do-while1.c 106 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 107 | ) 108 | 109 | add_test( 110 | NAME do-while2 111 | COMMAND ./test.sh do-while2 do-while2.c 112 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 113 | ) 114 | 115 | add_test( 116 | NAME switch0 117 | COMMAND ./test.sh switch0 switch0.c 118 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 119 | ) 120 | 121 | add_test( 122 | NAME switch1 123 | COMMAND ./test.sh switch1 switch1.c 124 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 125 | ) 126 | 127 | add_test( 128 | NAME switch2 129 | COMMAND ./test.sh switch2 switch2.c 130 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 131 | ) 132 | 133 | add_test( 134 | NAME switch3 135 | COMMAND ./test.sh switch3 switch3.c 136 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 137 | ) 138 | 139 | add_test( 140 | NAME function0 141 | COMMAND ./test.sh function0 function0.c 142 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 143 | ) 144 | 145 | add_test( 146 | NAME function1 147 | COMMAND ./test.sh function1 function1.c 148 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 149 | ) 150 | 151 | add_test( 152 | NAME dce0 153 | COMMAND ./test.sh dce0 dce0.c 154 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 155 | ) 156 | 157 | add_test( 158 | NAME dce1 159 | COMMAND ./test.sh dce1 dce1.c 160 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 161 | ) 162 | 163 | add_test( 164 | NAME dce2 165 | COMMAND ./test.sh dce2 dce2.c 166 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 167 | ) 168 | 169 | add_test( 170 | NAME dce3 171 | COMMAND ./test.sh dce3 dce3.c --skip_global --skip_local 172 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 173 | ) 174 | 175 | add_test( 176 | NAME dce4 177 | COMMAND ./test.sh dce4 dce4.c --skip_global --skip_local 178 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 179 | ) 180 | 181 | add_test( 182 | NAME label0 183 | COMMAND ./test.sh label0 label0.c 184 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 185 | ) 186 | 187 | add_test( 188 | NAME macro0 189 | COMMAND ./test.sh macro0 macro0.c 190 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 191 | ) 192 | 193 | add_test( 194 | NAME macro1 195 | COMMAND ./test.sh macro1 --build -- gcc -DMACRO=0 196 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 197 | ) 198 | 199 | add_test( 200 | NAME integration0 201 | COMMAND ./test.sh integration0 integration0.c subfile0.c subfile1.c 202 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 203 | ) 204 | 205 | add_test( 206 | NAME integration1 207 | COMMAND ./test.sh integration1 --build -- make 208 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" 209 | ) 210 | -------------------------------------------------------------------------------- /test/basic0/basic0.c: -------------------------------------------------------------------------------- 1 | int f1() { return 0; } 2 | int f2() { return 1; } 3 | int f3() { return 1; } 4 | int f4() { return 1; } 5 | int f5() { return 1; } 6 | int f6() { return 1; } 7 | int f7() { return 1; } 8 | int main() { return f1(); } 9 | -------------------------------------------------------------------------------- /test/basic0/basic0.c.answer.c: -------------------------------------------------------------------------------- 1 | int f1() { return 0; } 2 | 3 | int main() { return f1(); } 4 | -------------------------------------------------------------------------------- /test/basic0/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=basic0 4 | SRC=$NAME.c 5 | BIN=$NAME 6 | 7 | clang -w -o $BIN $SRC >& /dev/null || exit 1 8 | ./$BIN >& /dev/null || exit 1 9 | rm $BIN 10 | -------------------------------------------------------------------------------- /test/basic1/basic1.c: -------------------------------------------------------------------------------- 1 | typedef unsigned int uuint; 2 | struct x { 3 | int a; 4 | int b; 5 | int c; 6 | }; 7 | int var1; 8 | int f8(void) { return (0); } 9 | int f0(void) { return (23); } 10 | int f3(int i, int j, int x) { return (1); } 11 | union a { 12 | int z; 13 | }; 14 | int main(void) { 15 | struct x x_; 16 | printf("%d\n", f0()); 17 | x_.a = 2; 18 | goto this_label; 19 | this_label: 20 | return f0(); 21 | int z; 22 | } 23 | -------------------------------------------------------------------------------- /test/basic1/basic1.c.answer.c: -------------------------------------------------------------------------------- 1 | typedef unsigned int uuint; 2 | struct x { 3 | int a; 4 | int b; 5 | int c; 6 | }; 7 | 8 | int f0(void) { return (23); } 9 | 10 | union a { 11 | int z; 12 | }; 13 | int main(void) { 14 | 15 | printf("%d\n", f0()); 16 | 17 | return f0(); 18 | } 19 | -------------------------------------------------------------------------------- /test/basic1/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=basic1 4 | SRC=$NAME.c 5 | BIN=$NAME 6 | 7 | clang -w -o $BIN $SRC >& /dev/null || exit 1 8 | diff -q <(./$BIN) <(echo "23") >& /dev/null || exit 1 9 | rm $BIN 10 | -------------------------------------------------------------------------------- /test/basic2/basic2.c: -------------------------------------------------------------------------------- 1 | ; 2 | int main() { 3 | ; int i = 0; 4 | ; 5 | return i; 6 | ; 7 | ; 8 | } 9 | ; 10 | -------------------------------------------------------------------------------- /test/basic2/basic2.c.answer.c: -------------------------------------------------------------------------------- 1 | 2 | int main() { 3 | ; 4 | int i = 0; 5 | ; 6 | return i; 7 | ; 8 | ; 9 | } 10 | -------------------------------------------------------------------------------- /test/basic2/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=basic2 4 | SRC=$NAME.c 5 | BIN=$NAME 6 | 7 | clang -w -o $BIN $SRC >& /dev/null || exit 1 8 | ./$BIN >& /dev/null || exit 1 9 | rm $BIN 10 | -------------------------------------------------------------------------------- /test/basic3/basic3.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int x = 0; 3 | int y = 2; 4 | x--;x--;y++;x++;x++; 5 | return x; 6 | } 7 | -------------------------------------------------------------------------------- /test/basic3/basic3.c.answer.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int x = 0; 3 | 4 | return x; 5 | } 6 | -------------------------------------------------------------------------------- /test/basic3/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=basic3 4 | SRC=$NAME.c 5 | BIN=$NAME 6 | 7 | clang -w -o $BIN $SRC >& /dev/null || exit 1 8 | ./$BIN >& /dev/null || exit 1 9 | rm $BIN 10 | -------------------------------------------------------------------------------- /test/basic4/basic4.c: -------------------------------------------------------------------------------- 1 | char const diacrit_diac[4] = 2 | { (char const )3, (char const )2, (char const )4, (char const )6, 3 | }; 4 | char const opts[8] = 5 | { (char const )0, (char const )0, (char const )0, (char const )0, 6 | (char const )0, (char const )0, (char const )0, (char const )0, 7 | }; 8 | 9 | int main() { 10 | int x = 0; 11 | return x; 12 | } 13 | -------------------------------------------------------------------------------- /test/basic4/basic4.c.answer.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | int main() { 4 | int x = 0; 5 | return x; 6 | } 7 | -------------------------------------------------------------------------------- /test/basic4/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=basic4 4 | SRC=$NAME.c 5 | BIN=$NAME 6 | 7 | clang -w -o $BIN $SRC >& /dev/null || exit 1 8 | ./$BIN >& /dev/null || exit 1 9 | rm $BIN 10 | -------------------------------------------------------------------------------- /test/basic5/basic5.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int x; 3 | x = 0; 4 | return x; 5 | } 6 | -------------------------------------------------------------------------------- /test/basic5/basic5.c.answer.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int x; 3 | x = 0; 4 | return x; 5 | } 6 | -------------------------------------------------------------------------------- /test/basic5/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=basic5 4 | SRC=$NAME.c 5 | BIN=$NAME 6 | 7 | clang -w -o $BIN $SRC >& /dev/null || exit 1 8 | ./$BIN >& /dev/null || exit 1 9 | rm $BIN 10 | -------------------------------------------------------------------------------- /test/conditional0/conditional0.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x = 0; 3 | int y = 0; 4 | 5 | if(argc > 2) { 6 | y = 1; 7 | } else { 8 | y = 2; /* comment to be removed */ 9 | } 10 | 11 | if(argc > 2) 12 | y = 1 /* comment to be removed */ ; 13 | else 14 | y = 2 /* comment to be removed */ ; 15 | 16 | return x; 17 | } 18 | -------------------------------------------------------------------------------- /test/conditional0/conditional0.c.answer.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x = 0; 3 | 4 | return x; 5 | } 6 | -------------------------------------------------------------------------------- /test/conditional0/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BIN=conditional0 4 | SRC=$BIN.c 5 | 6 | clang -w -o $BIN $SRC >& /dev/null || exit 1 7 | ./$BIN || exit 1 8 | rm $BIN 9 | -------------------------------------------------------------------------------- /test/conditional1/conditional1.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x = 1; 3 | 4 | if(argc == 1) 5 | x--; 6 | else 7 | x++; 8 | 9 | return x; 10 | } 11 | -------------------------------------------------------------------------------- /test/conditional1/conditional1.c.answer.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x = 1; 3 | 4 | x--; 5 | 6 | return x; 7 | } 8 | -------------------------------------------------------------------------------- /test/conditional1/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BIN=conditional1 4 | SRC=$BIN.c 5 | 6 | clang -w -o $BIN $SRC >& /dev/null || exit 1 7 | ./$BIN || exit 1 8 | rm $BIN 9 | -------------------------------------------------------------------------------- /test/conditional2/conditional2.c: -------------------------------------------------------------------------------- 1 | int main(void) { 2 | int a = 5; 3 | if (a == 1) printf("12\n"); 4 | else if (a == 2) printf("13\n"); 5 | else printf("15\n"); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /test/conditional2/conditional2.c.answer.c: -------------------------------------------------------------------------------- 1 | int main(void) { 2 | 3 | printf("15\n"); 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /test/conditional2/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BIN=conditional2 4 | SRC=$BIN.c 5 | 6 | clang -w -o $BIN $SRC >& /dev/null || exit 1 7 | diff -q <(./$BIN) <(echo "15") >& /dev/null || exit 1 8 | rm $BIN 9 | -------------------------------------------------------------------------------- /test/conditional3/conditional3.c: -------------------------------------------------------------------------------- 1 | int main(void) { 2 | int a = 5; 3 | if ((a == 1)) printf("12\n"); 4 | else if ((a == 2)) printf("13\n"); 5 | else printf("15\n"); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /test/conditional3/conditional3.c.answer.c: -------------------------------------------------------------------------------- 1 | int main(void) { 2 | 3 | printf("15\n"); 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /test/conditional3/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BIN=conditional3 4 | SRC=$BIN.c 5 | 6 | clang -w -o $BIN $SRC >& /dev/null || exit 1 7 | diff -q <(./$BIN) <(echo "15") >& /dev/null || exit 1 8 | rm $BIN 9 | -------------------------------------------------------------------------------- /test/dce0/dce0.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int r = printf("3"); 3 | int x = 2; 4 | int q = x++; 5 | printf("%d\n", x); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /test/dce0/dce0.c.answer.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int r = printf("3"); 3 | int x = 2; 4 | int q = x++; 5 | printf("%d\n", x); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /test/dce0/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BIN=dce0 4 | SRC=$BIN.c 5 | 6 | clang -w -o $BIN $SRC >& /dev/null || exit 1 7 | diff -q <(./$BIN) <(echo "33") >& /dev/null || exit 1 8 | rm $BIN 9 | -------------------------------------------------------------------------------- /test/dce1/dce1.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x; 3 | if (argc > 2) { 4 | x = 0; 5 | } else { 6 | L: 7 | x = 0; 8 | } 9 | return x; 10 | } 11 | -------------------------------------------------------------------------------- /test/dce1/dce1.c.answer.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x; 3 | { x = 0; } 4 | 5 | return x; 6 | } 7 | -------------------------------------------------------------------------------- /test/dce1/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=dce1 4 | SRC=$NAME.c 5 | BIN=$NAME 6 | 7 | clang -w -o $BIN $SRC >& /dev/null || exit 1 8 | ./$BIN >& /dev/null || exit 1 9 | rm $BIN 10 | -------------------------------------------------------------------------------- /test/dce2/dce2.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int x = (int) 0; 3 | return 0; 4 | } 5 | -------------------------------------------------------------------------------- /test/dce2/dce2.c.answer.c: -------------------------------------------------------------------------------- 1 | int main() { return 0; } 2 | -------------------------------------------------------------------------------- /test/dce2/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=dce2 4 | SRC=$NAME.c 5 | BIN=$NAME 6 | 7 | clang -w -o $BIN $SRC >& /dev/null || exit 1 8 | ./$BIN >& /dev/null || exit 1 9 | rm $BIN 10 | -------------------------------------------------------------------------------- /test/dce3/dce3.c: -------------------------------------------------------------------------------- 1 | void empty1() { 2 | {} 3 | } 4 | 5 | void empty2(int x) { 6 | {} 7 | } 8 | 9 | int main() { 10 | int x; 11 | { 12 | { 13 | { 14 | x = 0; 15 | } 16 | } 17 | } 18 | return x; 19 | } 20 | -------------------------------------------------------------------------------- /test/dce3/dce3.c.answer.c: -------------------------------------------------------------------------------- 1 | void empty1() {} 2 | 3 | void empty2(int x) {} 4 | 5 | int main() { 6 | int x; 7 | { x = 0; } 8 | return x; 9 | } 10 | -------------------------------------------------------------------------------- /test/dce3/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=dce3 4 | SRC=$NAME.c 5 | BIN=$NAME 6 | 7 | clang -w -o $BIN $SRC >& /dev/null || exit 1 8 | ./$BIN >& /dev/null || exit 1 9 | rm $BIN 10 | -------------------------------------------------------------------------------- /test/dce4/dce4.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int x; 3 | int y = 10; 4 | // Compilers such as clang-7 raise warning for "int i" in for-statement. 5 | // DCE module should distinguish it from unsed-variable warnings 6 | for (int i = 0; i < 10; i++) { 7 | y--; 8 | } 9 | unused: 10 | return y; 11 | } 12 | -------------------------------------------------------------------------------- /test/dce4/dce4.c.answer.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | 3 | int y = 10; 4 | // Compilers such as clang-7 raise warning for "int i" in for-statement. 5 | // DCE module should distinguish it from unsed-variable warnings 6 | for (int i = 0; i < 10; i++) { 7 | y--; 8 | } 9 | 10 | return y; 11 | } 12 | -------------------------------------------------------------------------------- /test/dce4/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=dce4 4 | SRC=$NAME.c 5 | BIN=$NAME 6 | 7 | clang -w -o $BIN $SRC >&/dev/null || exit 1 8 | ./$BIN >&/dev/null || exit 1 9 | rm $BIN 10 | -------------------------------------------------------------------------------- /test/do-while0/do-while0.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x = 3; 3 | int y = 0; 4 | 5 | do{ 6 | x = 0; 7 | } while (x > 2); 8 | 9 | do y = 1; while(argc>2); 10 | 11 | return x; 12 | } 13 | -------------------------------------------------------------------------------- /test/do-while0/do-while0.c.answer.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x = 3; 3 | 4 | { x = 0; } 5 | 6 | return x; 7 | } 8 | -------------------------------------------------------------------------------- /test/do-while0/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BIN=do-while0 4 | SRC=$BIN.c 5 | 6 | clang -w -o $BIN $SRC >& /dev/null || exit 1 7 | ./$BIN || exit 1 8 | rm $BIN 9 | -------------------------------------------------------------------------------- /test/do-while1/do-while1.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x = 1; 3 | 4 | do x--; while(x); 5 | 6 | return x; 7 | } 8 | -------------------------------------------------------------------------------- /test/do-while1/do-while1.c.answer.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x = 1; 3 | 4 | x--; 5 | 6 | return x; 7 | } 8 | -------------------------------------------------------------------------------- /test/do-while1/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BIN=do-while1 4 | SRC=$BIN.c 5 | 6 | clang -w -o $BIN $SRC >& /dev/null || exit 1 7 | ./$BIN || exit 1 8 | rm $BIN 9 | -------------------------------------------------------------------------------- /test/do-while2/do-while2.c: -------------------------------------------------------------------------------- 1 | int main(void) { 2 | int a = 5; 3 | int x = 5; 4 | 5 | do { 6 | x--; 7 | do { 8 | x = 2; 9 | } while (x > 10); 10 | x = 0; 11 | printf("15\n"); 12 | } while (x); 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /test/do-while2/do-while2.c.answer.c: -------------------------------------------------------------------------------- 1 | int main(void) { 2 | 3 | { printf("15\n"); } 4 | 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /test/do-while2/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BIN=do-while2 4 | SRC=$BIN.c 5 | 6 | clang -w -o $BIN $SRC >& /dev/null || exit 1 7 | diff -q <(./$BIN) <(echo "15") >& /dev/null || exit 1 8 | rm $BIN 9 | -------------------------------------------------------------------------------- /test/for0/for0.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x = 1; 3 | int y = 3; 4 | int i; 5 | for(i=0; i<1; i++) 6 | x--; 7 | 8 | for(i=0; i<3; i++) { 9 | y--; 10 | } 11 | return x + y; 12 | } 13 | -------------------------------------------------------------------------------- /test/for0/for0.c.answer.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x = 1; 3 | int y = 3; 4 | int i; 5 | 6 | x--; 7 | 8 | for (i = 0; i < 3; i++) { 9 | y--; 10 | } 11 | return x + y; 12 | } 13 | -------------------------------------------------------------------------------- /test/for0/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BIN=for0 4 | SRC=$BIN.c 5 | 6 | clang -w -o $BIN $SRC >& /dev/null || exit 1 7 | ./$BIN || exit 1 8 | rm $BIN 9 | -------------------------------------------------------------------------------- /test/for1/for1.c: -------------------------------------------------------------------------------- 1 | int main(void) { 2 | int x = 1; 3 | int i; 4 | for (i = 2; i <= x + 2; i++) { 5 | printf("%d", i); 6 | } 7 | printf("\n"); 8 | for (i = 4; i > 0; i--) x--; 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /test/for1/for1.c.answer.c: -------------------------------------------------------------------------------- 1 | int main(void) { 2 | int x = 1; 3 | int i; 4 | for (i = 2; i <= x + 2; i++) { 5 | printf("%d", i); 6 | } 7 | printf("\n"); 8 | 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /test/for1/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=for1 4 | SRC=$NAME.c 5 | BIN=$NAME 6 | 7 | clang -w -o $BIN $SRC >& /dev/null || exit 1 8 | diff -q <(./$BIN) <(echo "23") >& /dev/null || exit 1 9 | rm $BIN 10 | -------------------------------------------------------------------------------- /test/for2/for2.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x = 1; 3 | int i; 4 | 5 | for (i = 0; i < 1; i++) 6 | for(;x;) 7 | x--; 8 | 9 | return x; 10 | } 11 | -------------------------------------------------------------------------------- /test/for2/for2.c.answer.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x = 1; 3 | 4 | x--; 5 | 6 | return x; 7 | } 8 | -------------------------------------------------------------------------------- /test/for2/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BIN=for2 4 | SRC=$BIN.c 5 | 6 | clang -w -o $BIN $SRC >& /dev/null || exit 1 7 | ./$BIN || exit 1 8 | rm $BIN 9 | -------------------------------------------------------------------------------- /test/for3/for3.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int i; 3 | for(i = 0;;) { 4 | i++; 5 | return 0; 6 | } 7 | 8 | return 1; 9 | } 10 | -------------------------------------------------------------------------------- /test/for3/for3.c.answer.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { return 0; } 2 | -------------------------------------------------------------------------------- /test/for3/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BIN=for3 4 | SRC=$BIN.c 5 | 6 | clang -w -o $BIN $SRC >&/dev/null || exit 1 7 | ./$BIN || exit 1 8 | rm $BIN 9 | -------------------------------------------------------------------------------- /test/function0/function0.c: -------------------------------------------------------------------------------- 1 | int z(int i, int j) { 2 | int p; 3 | p = i + j - 3; 4 | int k; 5 | k = i + j + 10; 6 | return p; 7 | } 8 | 9 | int main() { 10 | int i; 11 | i = z(6, 4); 12 | printf("%d\n", i); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /test/function0/function0.c.answer.c: -------------------------------------------------------------------------------- 1 | int z(int i, int j) { 2 | int p; 3 | p = i + j - 3; 4 | 5 | return p; 6 | } 7 | 8 | int main() { 9 | int i; 10 | i = z(6, 4); 11 | printf("%d\n", i); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /test/function0/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BIN=function0 4 | SRC=$BIN.c 5 | 6 | clang -w -o $BIN $SRC >& /dev/null || exit 1 7 | diff -q <(./$BIN) <(echo "7") >& /dev/null || exit 1 8 | rm $BIN 9 | -------------------------------------------------------------------------------- /test/function1/function1.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int p = 10; 3 | int i; 4 | i = p - 3; 5 | int k; 6 | k = p + i; 7 | printf("%d\n", i); 8 | } 9 | -------------------------------------------------------------------------------- /test/function1/function1.c.answer.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int p = 10; 3 | int i; 4 | i = p - 3; 5 | 6 | printf("%d\n", i); 7 | } 8 | -------------------------------------------------------------------------------- /test/function1/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BIN=function1 4 | SRC=$BIN.c 5 | 6 | clang -w -o $BIN $SRC >& /dev/null || exit 1 7 | diff -q <(./$BIN) <(echo "7") >& /dev/null || exit 1 8 | rm $BIN 9 | -------------------------------------------------------------------------------- /test/integration0/header.h: -------------------------------------------------------------------------------- 1 | int in_header() { return 1; } 2 | -------------------------------------------------------------------------------- /test/integration0/integration0.c: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | 3 | extern int g(); 4 | 5 | int f() { return 0; } 6 | 7 | int main() { 8 | int x; 9 | int y; 10 | y = g(); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /test/integration0/integration0.c.answer.c: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | 3 | extern int g(); 4 | 5 | int main() { return 0; } 6 | -------------------------------------------------------------------------------- /test/integration0/subfile0.c: -------------------------------------------------------------------------------- 1 | int g() { return 0; } 2 | -------------------------------------------------------------------------------- /test/integration0/subfile0.c.answer.c: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/integration0/subfile1.c: -------------------------------------------------------------------------------- 1 | int unused = 0; 2 | -------------------------------------------------------------------------------- /test/integration0/subfile1.c.answer.c: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/integration0/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=integration0 4 | SRC=$NAME.c 5 | BIN=$NAME 6 | 7 | clang -w -c subfile0.c >&/dev/null || exit 1 8 | clang -w -c subfile1.c >&/dev/null || exit 1 9 | clang -w -o $BIN $SRC subfile0.o subfile1.o >&/dev/null || exit 1 10 | ./$BIN >&/dev/null || exit 1 11 | rm $BIN 12 | -------------------------------------------------------------------------------- /test/integration1/Makefile: -------------------------------------------------------------------------------- 1 | all: integration1.o subfile0.o subfile1.o 2 | clang -o integration1 subfile0.o subfile1.o integration1.o 3 | 4 | %.o: %.c 5 | clang -I ./include -c $< -o $@ 6 | 7 | clean: 8 | rm -rf *.o integration1 9 | -------------------------------------------------------------------------------- /test/integration1/include/header.h: -------------------------------------------------------------------------------- 1 | int in_header() { return 1; } 2 | -------------------------------------------------------------------------------- /test/integration1/integration1.c: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | 3 | extern int g(); 4 | 5 | int f() { return 0; } 6 | 7 | int main() { 8 | int x; 9 | int y; 10 | y = g(); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /test/integration1/integration1.c.answer.c: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | 3 | extern int g(); 4 | 5 | int main() { return 0; } 6 | -------------------------------------------------------------------------------- /test/integration1/subfile0.c: -------------------------------------------------------------------------------- 1 | int g() { return 0; } 2 | -------------------------------------------------------------------------------- /test/integration1/subfile0.c.answer.c: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/integration1/subfile1.c: -------------------------------------------------------------------------------- 1 | int unused = 0; 2 | -------------------------------------------------------------------------------- /test/integration1/subfile1.c.answer.c: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/integration1/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=integration1 4 | SRC=$NAME.c 5 | BIN=$NAME 6 | 7 | make >&/dev/null || exit 1 8 | ./$BIN >&/dev/null || exit 1 9 | make clean >&/dev/null 10 | -------------------------------------------------------------------------------- /test/label0/label0.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | int x; 3 | if (argc == 1) { 4 | goto case1; 5 | } 6 | if (argc == 9) { 7 | goto case9; 8 | } 9 | case1: 10 | x = 0; 11 | goto breaklabel; 12 | case9: 13 | x = 1; 14 | goto breaklabel; 15 | breaklabel: 16 | return x; 17 | } 18 | -------------------------------------------------------------------------------- /test/label0/label0.c.answer.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x; 3 | 4 | x = 0; 5 | 6 | return x; 7 | } 8 | -------------------------------------------------------------------------------- /test/label0/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | clang -w label0.c 4 | ./a.out 5 | -------------------------------------------------------------------------------- /test/loop0/loop0.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x = 0; 3 | int y = 0; 4 | 5 | while(argc > 2) { 6 | y = 2; /* comment to be removed */ 7 | } 8 | 9 | while(argc > 2) 10 | y = 1 /* comment to be removed */ ; 11 | 12 | return x; 13 | } 14 | -------------------------------------------------------------------------------- /test/loop0/loop0.c.answer.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x = 0; 3 | 4 | return x; 5 | } 6 | -------------------------------------------------------------------------------- /test/loop0/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BIN=loop0 4 | SRC=$BIN.c 5 | 6 | clang -w -o $BIN $SRC >& /dev/null || exit 1 7 | ./$BIN || exit 1 8 | rm $BIN 9 | -------------------------------------------------------------------------------- /test/loop1/loop1.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x = 1; 3 | 4 | while(x) 5 | x--; 6 | 7 | return x; 8 | } 9 | -------------------------------------------------------------------------------- /test/loop1/loop1.c.answer.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x = 1; 3 | 4 | x--; 5 | 6 | return x; 7 | } 8 | -------------------------------------------------------------------------------- /test/loop1/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BIN=loop1 4 | SRC=$BIN.c 5 | 6 | clang -w -o $BIN $SRC >& /dev/null || exit 1 7 | ./$BIN || exit 1 8 | rm $BIN 9 | -------------------------------------------------------------------------------- /test/macro0/macro0.c: -------------------------------------------------------------------------------- 1 | #define FUNCTION_CALL f() 2 | #define X_EQUAL x= 3 | #define ONE 1 4 | #define FUNCTION_DEF void g() { return; } 5 | 6 | int f() { return 1; } 7 | 8 | 9 | int main() { 10 | int x; 11 | x = FUNCTION_CALL; 12 | X_EQUAL 1; 13 | return ONE - 1; 14 | } 15 | -------------------------------------------------------------------------------- /test/macro0/macro0.c.answer.c: -------------------------------------------------------------------------------- 1 | #define FUNCTION_CALL f() 2 | #define X_EQUAL x = 3 | #define ONE 1 4 | #define FUNCTION_DEF \ 5 | void g() { return; } 6 | 7 | int main() { return ONE - 1; } 8 | -------------------------------------------------------------------------------- /test/macro0/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=macro0 4 | SRC=$NAME.c 5 | BIN=$NAME 6 | 7 | clang -w -o $BIN $SRC >&/dev/null || exit 1 8 | ./$BIN >&/dev/null || exit 1 9 | rm $BIN 10 | -------------------------------------------------------------------------------- /test/macro1/macro1.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int x = 0; 3 | x = MACRO; 4 | x--; 5 | x = 0; 6 | return x; 7 | } 8 | -------------------------------------------------------------------------------- /test/macro1/macro1.c.answer.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int x = 0; 3 | 4 | return x; 5 | } 6 | -------------------------------------------------------------------------------- /test/macro1/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=macro1 4 | SRC=$NAME.c 5 | BIN=$NAME 6 | 7 | clang -w -o $BIN -DMACRO=1 $SRC >&/dev/null || exit 1 8 | timeout 0.1 ./$BIN >&/dev/null || exit 1 9 | rm $BIN 10 | -------------------------------------------------------------------------------- /test/switch0/switch0.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x = 0; 3 | int y = 3; 4 | switch(y) { 5 | case 0: 6 | y = 3; 7 | break; 8 | case 2: 9 | y = 1; 10 | break; 11 | case 3: 12 | y = 0; 13 | break; 14 | default: 15 | y = 10; 16 | } 17 | return x + y; 18 | } 19 | -------------------------------------------------------------------------------- /test/switch0/switch0.c.answer.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int x = 0; 3 | int y = 3; 4 | switch (y) { 5 | 6 | case 3: 7 | y = 0; 8 | break; 9 | } 10 | return x + y; 11 | } 12 | -------------------------------------------------------------------------------- /test/switch0/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BIN=switch0 4 | SRC=$BIN.c 5 | 6 | clang -w -o $BIN $SRC >& /dev/null || exit 1 7 | ./$BIN || exit 1 8 | rm $BIN 9 | -------------------------------------------------------------------------------- /test/switch1/switch1.c: -------------------------------------------------------------------------------- 1 | int main(void) { 2 | int x = 1; 3 | switch (x) { 4 | case 1: 5 | printf("%d", 2); 6 | printf("%d\n", 3); 7 | break; 8 | case 2: 9 | printf("%d\n", 34); 10 | break; 11 | } 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /test/switch1/switch1.c.answer.c: -------------------------------------------------------------------------------- 1 | int main(void) { 2 | int x = 1; 3 | switch (x) { 4 | case 1: 5 | printf("%d", 2); 6 | printf("%d\n", 3); 7 | break; 8 | } 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /test/switch1/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=switch1 4 | SRC=$NAME.c 5 | BIN=$NAME 6 | 7 | clang -w -o $BIN $SRC >& /dev/null || exit 1 8 | diff -q <(./$BIN) <(echo "23") >& /dev/null || exit 1 9 | rm $BIN 10 | -------------------------------------------------------------------------------- /test/switch2/switch2.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | char i = 'a'; 3 | float x = 0.2; 4 | switch (i) { 5 | case 'a': 6 | if (x > 0.1) 7 | printf("%c\n", i); 8 | break; 9 | case 'b': { 10 | for (; !i;) 11 | printf("not this statement.\n"); 12 | } 13 | } 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /test/switch2/switch2.c.answer.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | char i = 'a'; 3 | float x = 0.2; 4 | switch (i) { 5 | case 'a': 6 | if (x > 0.1) 7 | printf("%c\n", i); 8 | break; 9 | } 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /test/switch2/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=switch2 4 | SRC=$NAME.c 5 | BIN=$NAME 6 | 7 | clang -w -o $BIN $SRC >& /dev/null || exit 1 8 | diff -q <(./$BIN) <(echo "a") >& /dev/null || exit 1 9 | rm $BIN 10 | -------------------------------------------------------------------------------- /test/switch3/switch3.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int c = 2; 3 | int x = 1; 4 | switch (c) { 5 | case 1: 6 | x = 1; 7 | break; 8 | case 2: 9 | x = 0; 10 | break; 11 | case 3: 12 | x = 2; 13 | break; 14 | } 15 | return x; 16 | } 17 | -------------------------------------------------------------------------------- /test/switch3/switch3.c.answer.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int c = 2; 3 | int x = 1; 4 | switch (c) { 5 | 6 | case 2: 7 | x = 0; 8 | break; 9 | } 10 | return x; 11 | } 12 | -------------------------------------------------------------------------------- /test/switch3/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=switch3 4 | SRC=$NAME.c 5 | BIN=$NAME 6 | 7 | clang -w -o $BIN $SRC >&/dev/null || exit 1 8 | ./$BIN >&/dev/null || exit 1 9 | rm $BIN 10 | -------------------------------------------------------------------------------- /test/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CHISEL_HOME=$(cd $(dirname ${BASH_SOURCE[0]}) && cd ../ && pwd) 4 | CHISEL=$CHISEL_HOME/build/bin/chisel 5 | TEST_NAME=$1 6 | ARGS="${@:2}" 7 | 8 | cd $CHISEL_HOME/test/$TEST_NAME 9 | 10 | rm -rf $TEST_NAME $TEST_NAME.c.chisel.c chisel-out *.o 11 | 12 | $CHISEL $OPTIONS ./test.sh $ARGS 13 | 14 | rm -rf $TEST_NAME *.o 15 | 16 | for SRC in $ARGS; do 17 | if [[ $SRC == *.c ]]; then 18 | diff -q $SRC.chisel.c $SRC.answer.c || exit 1 19 | fi 20 | done 21 | 22 | rm -rf *.chisel.c *.origin.c chisel-out 23 | --------------------------------------------------------------------------------