Compare commits
1 Commits
master
...
testing/re
| Author | SHA1 | Date | |
|---|---|---|---|
| 9bc37e23ae |
@ -1,66 +0,0 @@
|
|||||||
# Generated from CLion C/C++ Code Style settings
|
|
||||||
BasedOnStyle: LLVM
|
|
||||||
AccessModifierOffset: -2
|
|
||||||
AlignAfterOpenBracket: Align
|
|
||||||
AlignConsecutiveAssignments: false
|
|
||||||
AlignOperands: true
|
|
||||||
AllowAllArgumentsOnNextLine: false
|
|
||||||
AllowAllConstructorInitializersOnNextLine: false
|
|
||||||
AllowAllParametersOfDeclarationOnNextLine: false
|
|
||||||
AllowShortBlocksOnASingleLine: Always
|
|
||||||
AllowShortCaseLabelsOnASingleLine: false
|
|
||||||
AllowShortFunctionsOnASingleLine: All
|
|
||||||
AllowShortIfStatementsOnASingleLine: Always
|
|
||||||
AllowShortLambdasOnASingleLine: All
|
|
||||||
AllowShortLoopsOnASingleLine: true
|
|
||||||
AlwaysBreakAfterReturnType: None
|
|
||||||
AlwaysBreakTemplateDeclarations: Yes
|
|
||||||
BreakBeforeBraces: Custom
|
|
||||||
BraceWrapping:
|
|
||||||
AfterCaseLabel: false
|
|
||||||
AfterClass: true
|
|
||||||
AfterControlStatement: Always
|
|
||||||
AfterEnum: true
|
|
||||||
AfterFunction: true
|
|
||||||
AfterNamespace: true
|
|
||||||
AfterUnion: true
|
|
||||||
BeforeCatch: false
|
|
||||||
BeforeElse: false
|
|
||||||
IndentBraces: false
|
|
||||||
SplitEmptyFunction: false
|
|
||||||
SplitEmptyRecord: true
|
|
||||||
BreakBeforeBinaryOperators: None
|
|
||||||
BreakBeforeTernaryOperators: true
|
|
||||||
BreakConstructorInitializers: BeforeColon
|
|
||||||
BreakInheritanceList: BeforeComma
|
|
||||||
ColumnLimit: 0
|
|
||||||
CompactNamespaces: false
|
|
||||||
ContinuationIndentWidth: 8
|
|
||||||
IndentCaseLabels: true
|
|
||||||
IndentPPDirectives: None
|
|
||||||
IndentWidth: 2
|
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
|
||||||
MaxEmptyLinesToKeep: 2
|
|
||||||
NamespaceIndentation: None
|
|
||||||
ObjCSpaceAfterProperty: false
|
|
||||||
ObjCSpaceBeforeProtocolList: true
|
|
||||||
PointerAlignment: Left
|
|
||||||
ReflowComments: false
|
|
||||||
SpaceAfterCStyleCast: true
|
|
||||||
SpaceAfterLogicalNot: false
|
|
||||||
SpaceAfterTemplateKeyword: false
|
|
||||||
SpaceBeforeAssignmentOperators: true
|
|
||||||
SpaceBeforeCpp11BracedList: false
|
|
||||||
SpaceBeforeCtorInitializerColon: true
|
|
||||||
SpaceBeforeInheritanceColon: true
|
|
||||||
SpaceBeforeParens: ControlStatements
|
|
||||||
SpaceBeforeRangeBasedForLoopColon: true
|
|
||||||
SpaceInEmptyParentheses: false
|
|
||||||
SpacesBeforeTrailingComments: 0
|
|
||||||
SpacesInAngles: false
|
|
||||||
SpacesInCStyleCastParentheses: false
|
|
||||||
SpacesInContainerLiterals: false
|
|
||||||
SpacesInParentheses: false
|
|
||||||
SpacesInSquareBrackets: false
|
|
||||||
TabWidth: 2
|
|
||||||
UseTab: Never
|
|
||||||
36
.drone.yml
36
.drone.yml
@ -1,36 +0,0 @@
|
|||||||
kind: pipeline
|
|
||||||
type: docker
|
|
||||||
name: default
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: build and test
|
|
||||||
pull: never
|
|
||||||
image: erki/llvm:latest
|
|
||||||
commands:
|
|
||||||
- apt install --no-install-recommends python3-pip -y
|
|
||||||
- pip3 install --upgrade conan
|
|
||||||
- conan profile new default --detect
|
|
||||||
- conan profile update settings.compiler.libcxx=libstdc++11 default
|
|
||||||
- mkdir -p build
|
|
||||||
- cd build
|
|
||||||
- conan install .. --build=missing
|
|
||||||
- cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=ON
|
|
||||||
- ninja
|
|
||||||
- ctest . --output-on-failure
|
|
||||||
- name: opsummarizer integration tests
|
|
||||||
pull: never
|
|
||||||
image: erki/llvm:latest
|
|
||||||
commands:
|
|
||||||
- apt install --no-install-recommends gcovr python3-pip -y
|
|
||||||
- pip3 install --upgrade conan
|
|
||||||
- conan profile new default --detect
|
|
||||||
- conan profile update settings.compiler.libcxx=libstdc++11 default
|
|
||||||
- mkdir -p build
|
|
||||||
- cd build
|
|
||||||
- conan install .. --build=missing
|
|
||||||
- cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=OFF
|
|
||||||
- ninja op-finder
|
|
||||||
- cp -r ../testcases ./testcases
|
|
||||||
- cd ./testcases
|
|
||||||
- ln ../op-finder/op-finder ./op-finder
|
|
||||||
- python3 ../../op-summarizer/tests.py
|
|
||||||
144
.gitignore
vendored
144
.gitignore
vendored
@ -1,7 +1,3 @@
|
|||||||
## Project specifics
|
|
||||||
testcases/*/
|
|
||||||
|
|
||||||
## C & C++
|
|
||||||
# Prerequisites
|
# Prerequisites
|
||||||
*.d
|
*.d
|
||||||
|
|
||||||
@ -38,143 +34,3 @@ testcases/*/
|
|||||||
# Build folders
|
# Build folders
|
||||||
[Bb]uild/
|
[Bb]uild/
|
||||||
cmake-*/
|
cmake-*/
|
||||||
|
|
||||||
## Python.
|
|
||||||
# Byte-compiled / optimized / DLL files
|
|
||||||
__pycache__/
|
|
||||||
*.py[cod]
|
|
||||||
*$py.class
|
|
||||||
|
|
||||||
# C extensions
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Distribution / packaging
|
|
||||||
.Python
|
|
||||||
build/
|
|
||||||
develop-eggs/
|
|
||||||
dist/
|
|
||||||
downloads/
|
|
||||||
eggs/
|
|
||||||
.eggs/
|
|
||||||
lib/
|
|
||||||
lib64/
|
|
||||||
parts/
|
|
||||||
sdist/
|
|
||||||
var/
|
|
||||||
wheels/
|
|
||||||
share/python-wheels/
|
|
||||||
*.egg-info/
|
|
||||||
.installed.cfg
|
|
||||||
*.egg
|
|
||||||
MANIFEST
|
|
||||||
|
|
||||||
# PyInstaller
|
|
||||||
# Usually these files are written by a python script from a template
|
|
||||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
||||||
*.manifest
|
|
||||||
*.spec
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
pip-delete-this-directory.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
htmlcov/
|
|
||||||
.tox/
|
|
||||||
.nox/
|
|
||||||
.coverage
|
|
||||||
.coverage.*
|
|
||||||
.cache
|
|
||||||
nosetests.xml
|
|
||||||
coverage.xml
|
|
||||||
*.cover
|
|
||||||
*.py,cover
|
|
||||||
.hypothesis/
|
|
||||||
.pytest_cache/
|
|
||||||
cover/
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
*.mo
|
|
||||||
*.pot
|
|
||||||
|
|
||||||
# Django stuff:
|
|
||||||
*.log
|
|
||||||
local_settings.py
|
|
||||||
db.sqlite3
|
|
||||||
db.sqlite3-journal
|
|
||||||
|
|
||||||
# Flask stuff:
|
|
||||||
instance/
|
|
||||||
.webassets-cache
|
|
||||||
|
|
||||||
# Scrapy stuff:
|
|
||||||
.scrapy
|
|
||||||
|
|
||||||
# Sphinx documentation
|
|
||||||
docs/_build/
|
|
||||||
|
|
||||||
# PyBuilder
|
|
||||||
.pybuilder/
|
|
||||||
target/
|
|
||||||
|
|
||||||
# Jupyter Notebook
|
|
||||||
.ipynb_checkpoints
|
|
||||||
|
|
||||||
# IPython
|
|
||||||
profile_default/
|
|
||||||
ipython_config.py
|
|
||||||
|
|
||||||
# pyenv
|
|
||||||
# For a library or package, you might want to ignore these files since the code is
|
|
||||||
# intended to run in multiple environments; otherwise, check them in:
|
|
||||||
# .python-version
|
|
||||||
|
|
||||||
# pipenv
|
|
||||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
||||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
||||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
||||||
# install all needed dependencies.
|
|
||||||
#Pipfile.lock
|
|
||||||
|
|
||||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
|
||||||
__pypackages__/
|
|
||||||
|
|
||||||
# Celery stuff
|
|
||||||
celerybeat-schedule
|
|
||||||
celerybeat.pid
|
|
||||||
|
|
||||||
# SageMath parsed files
|
|
||||||
*.sage.py
|
|
||||||
|
|
||||||
# Environments
|
|
||||||
.env
|
|
||||||
.venv
|
|
||||||
env/
|
|
||||||
venv/
|
|
||||||
ENV/
|
|
||||||
env.bak/
|
|
||||||
venv.bak/
|
|
||||||
|
|
||||||
# Spyder project settings
|
|
||||||
.spyderproject
|
|
||||||
.spyproject
|
|
||||||
|
|
||||||
# Rope project settings
|
|
||||||
.ropeproject
|
|
||||||
|
|
||||||
# mkdocs documentation
|
|
||||||
/site
|
|
||||||
|
|
||||||
# mypy
|
|
||||||
.mypy_cache/
|
|
||||||
.dmypy.json
|
|
||||||
dmypy.json
|
|
||||||
|
|
||||||
# Pyre type checker
|
|
||||||
.pyre/
|
|
||||||
|
|
||||||
# pytype static type analyzer
|
|
||||||
.pytype/
|
|
||||||
|
|
||||||
# Cython debug symbols
|
|
||||||
cython_debug/
|
|
||||||
|
|||||||
8
.idea/.gitignore
generated
vendored
8
.idea/.gitignore
generated
vendored
@ -1,8 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Datasource local storage ignored files
|
|
||||||
/dataSources/
|
|
||||||
/dataSources.local.xml
|
|
||||||
# Editor-based HTTP Client requests
|
|
||||||
/httpRequests/
|
|
||||||
1
.idea/.name
generated
1
.idea/.name
generated
@ -1 +0,0 @@
|
|||||||
C Analyzer
|
|
||||||
2
.idea/analyzer.git.iml
generated
2
.idea/analyzer.git.iml
generated
@ -1,2 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
|
||||||
59
.idea/codeStyles/Project.xml
generated
59
.idea/codeStyles/Project.xml
generated
@ -1,59 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<code_scheme name="Project" version="173">
|
|
||||||
<Objective-C>
|
|
||||||
<option name="INDENT_NAMESPACE_MEMBERS" value="0" />
|
|
||||||
<option name="INDENT_C_STRUCT_MEMBERS" value="2" />
|
|
||||||
<option name="INDENT_CLASS_MEMBERS" value="2" />
|
|
||||||
<option name="INDENT_INSIDE_CODE_BLOCK" value="2" />
|
|
||||||
<option name="NAMESPACE_BRACE_PLACEMENT" value="2" />
|
|
||||||
<option name="FUNCTION_BRACE_PLACEMENT" value="2" />
|
|
||||||
<option name="BLOCK_BRACE_PLACEMENT" value="2" />
|
|
||||||
<option name="SUPERCLASS_LIST_COMMA_ON_NEXT_LINE" value="true" />
|
|
||||||
<option name="SPACE_WITHIN_EMPTY_BRACES" value="true" />
|
|
||||||
<option name="SPACE_BEFORE_POINTER_IN_DECLARATION" value="false" />
|
|
||||||
<option name="SPACE_AFTER_POINTER_IN_DECLARATION" value="true" />
|
|
||||||
<option name="SPACE_BEFORE_REFERENCE_IN_DECLARATION" value="false" />
|
|
||||||
<option name="SPACE_AFTER_REFERENCE_IN_DECLARATION" value="true" />
|
|
||||||
</Objective-C>
|
|
||||||
<Objective-C-extensions>
|
|
||||||
<extensions>
|
|
||||||
<pair source="cpp" header="hpp" fileNamingConvention="PASCAL_CASE" />
|
|
||||||
<pair source="c" header="h" fileNamingConvention="NONE" />
|
|
||||||
<pair source="cu" header="cuh" fileNamingConvention="NONE" />
|
|
||||||
</extensions>
|
|
||||||
<rules>
|
|
||||||
<rule entity="NAMESPACE" visibility="ANY" specifier="ANY" prefix="" style="CAMEL_CASE" suffix="" />
|
|
||||||
<rule entity="MACRO" visibility="ANY" specifier="ANY" prefix="" style="SCREAMING_SNAKE_CASE" suffix="" />
|
|
||||||
<rule entity="CLASS" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
|
||||||
<rule entity="STRUCT" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
|
||||||
<rule entity="ENUM" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
|
||||||
<rule entity="ENUMERATOR" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
|
||||||
<rule entity="TYPEDEF" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
|
||||||
<rule entity="UNION" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
|
||||||
<rule entity="CLASS_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="CAMEL_CASE" suffix="" />
|
|
||||||
<rule entity="STRUCT_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="CAMEL_CASE" suffix="" />
|
|
||||||
<rule entity="CLASS_MEMBER_FIELD" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
|
||||||
<rule entity="STRUCT_MEMBER_FIELD" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
|
||||||
<rule entity="GLOBAL_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
|
||||||
<rule entity="GLOBAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
|
||||||
<rule entity="PARAMETER" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
|
||||||
<rule entity="LOCAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
|
||||||
<rule entity="CLASS_MEMBER_FIELD,STRUCT_MEMBER_FIELD" visibility="PROTECTED,PRIVATE" specifier="ANY" prefix="_" style="SNAKE_CASE" suffix="" />
|
|
||||||
<rule entity="CLASS_MEMBER_FUNCTION,STRUCT_MEMBER_FUNCTION" visibility="PROTECTED,PRIVATE" specifier="ANY" prefix="_" style="PASCAL_CASE" suffix="" />
|
|
||||||
</rules>
|
|
||||||
</Objective-C-extensions>
|
|
||||||
<codeStyleSettings language="CMake">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="ObjectiveC">
|
|
||||||
<option name="BRACE_STYLE" value="2" />
|
|
||||||
<option name="CLASS_BRACE_STYLE" value="2" />
|
|
||||||
<indentOptions>
|
|
||||||
<option name="INDENT_SIZE" value="2" />
|
|
||||||
<option name="TAB_SIZE" value="2" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
</code_scheme>
|
|
||||||
</component>
|
|
||||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
5
.idea/codeStyles/codeStyleConfig.xml
generated
@ -1,5 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<state>
|
|
||||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
|
||||||
</state>
|
|
||||||
</component>
|
|
||||||
4
.idea/misc.xml
generated
4
.idea/misc.xml
generated
@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
|
||||||
</project>
|
|
||||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/analyzer.git.iml" filepath="$PROJECT_DIR$/.idea/analyzer.git.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@ -1,16 +1,8 @@
|
|||||||
cmake_minimum_required(VERSION 3.14)
|
cmake_minimum_required(VERSION 3.17)
|
||||||
project("C Analyzer")
|
project("C Analyzer")
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter")
|
||||||
|
|
||||||
option(WITH_TESTS "Build unit tests as well." OFF)
|
|
||||||
|
|
||||||
add_subdirectory(op-finder-lib)
|
|
||||||
add_subdirectory(op-finder)
|
add_subdirectory(op-finder)
|
||||||
|
|
||||||
if(WITH_TESTS)
|
|
||||||
enable_testing()
|
|
||||||
add_subdirectory(op-finder-tests)
|
|
||||||
endif()
|
|
||||||
|
|||||||
16
Dockerfile
16
Dockerfile
@ -1,16 +0,0 @@
|
|||||||
FROM ubuntu:20.04
|
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND noninteractive
|
|
||||||
|
|
||||||
RUN apt-get update -y
|
|
||||||
RUN apt-get install -y git build-essential cmake ninja-build python3 python3-pip
|
|
||||||
|
|
||||||
RUN git clone --depth=1 https://github.com/llvm/llvm-project.git
|
|
||||||
|
|
||||||
RUN mkdir /llvm-project/build
|
|
||||||
WORKDIR /llvm-project/build
|
|
||||||
RUN cmake ../llvm -G"Ninja" -DLLVM_ENABLE_PROJECTS="clang" -DCMAKE_BUILD_TYPE=Release
|
|
||||||
RUN ninja install
|
|
||||||
|
|
||||||
WORKDIR /
|
|
||||||
RUN rm -r /llvm-project
|
|
||||||
2
LICENSE
2
LICENSE
@ -1,4 +1,4 @@
|
|||||||
MIT License Copyright (c) 2021 Erki Meinberg
|
MIT License Copyright (c) <year> <copyright holders>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
124
README.md
124
README.md
@ -1,124 +1,2 @@
|
|||||||
# clang Based Atomic Operations Parser & Analyzer
|
# masters-thesis
|
||||||
|
|
||||||
The source code attached for a master's thesis work carried out in 2021.
|
|
||||||
Contained within is the source code for an **Atomic Operations Parser** and
|
|
||||||
a **Performance Analyzer**.
|
|
||||||
|
|
||||||
## Atomic Operations Parser (Operatioon Finder)
|
|
||||||
|
|
||||||
The **Atomic Operations Parser** is a C++ program which is meant to parse C-code
|
|
||||||
source files, and extract atomic operations from them. The tool uses LLVM & clang.
|
|
||||||
So precompiling the development libraries of those two is required.
|
|
||||||
|
|
||||||
### Building LLVM & clang
|
|
||||||
|
|
||||||
A docker file which automatically compiles and installs the required dependencies
|
|
||||||
is included for convenience.
|
|
||||||
|
|
||||||
Otherwise, the steps to installing clang are as follows:
|
|
||||||
|
|
||||||
Install the required dependencies via apt:
|
|
||||||
```shell
|
|
||||||
apt update -y
|
|
||||||
apt install -y git build-essential cmake ninja-build python3 python3-pip
|
|
||||||
```
|
|
||||||
|
|
||||||
Clone LLVM from the repo. Depth 1 makes the process faster. Also set up the various
|
|
||||||
folders for building and installing.
|
|
||||||
```shell
|
|
||||||
cd ~
|
|
||||||
git clone --branch "release/11.x" --depth 1 https://github.com/llvm/llvm-project.git
|
|
||||||
mkdir ~/llvm-project/build
|
|
||||||
mkdir ~/llvm-install
|
|
||||||
cd ~/llvm-project/build
|
|
||||||
```
|
|
||||||
|
|
||||||
Run cmake to configure the project. Followed by ninja to install it.
|
|
||||||
Note that when installing, you can modify `-DCMAKE_INSTALL_PREFIX` to specify
|
|
||||||
where the libraries should be installed to. In this case, we'll put them into
|
|
||||||
`~/llvm-install`.
|
|
||||||
```shell
|
|
||||||
cmake ../llvm -G "Ninja" -DCMAKE_INSTALL_PREFIX=~/llvm-install -DLLVM_ENABLE_PROJECTS="clang" -DCMAKE_BUILD_TYPE=Release
|
|
||||||
ninja install
|
|
||||||
```
|
|
||||||
|
|
||||||
### Building the Tool
|
|
||||||
|
|
||||||
Using the conan package manager is recommended. Otherwise you have to provide `Catch2_ROOT`
|
|
||||||
and `nlohmann_json_ROOT` yourself.
|
|
||||||
|
|
||||||
The variables `Clang_ROOT` and `LLVM_ROOT` depend on the previous step. If you installed the libraries
|
|
||||||
into your system, then you don't need to specify them. Otherwise, assuming an installation directory of
|
|
||||||
`~/llvm_install`, they'd look as follows:
|
|
||||||
```
|
|
||||||
-DClang_ROOT=~/llvm_install/lib/cmake/clang/
|
|
||||||
-DLLVM_ROOT=~/llvm_install/lib/cmake/llvm/
|
|
||||||
```
|
|
||||||
|
|
||||||
Now clone this repo and `cd` inside of it. Make a build directory and build the project:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
conan install .. --build=missing
|
|
||||||
export CLANG_ROOT=~/llvm_install/lib/cmake/clang/
|
|
||||||
export LLVM_ROOT=~/llvm_install/lib/cmake/llvm/
|
|
||||||
cmake .. -DWITH_TESTS=ON -DClang_ROOT=${CLANG_ROOT} -DLLVM_ROOT=${LLVM_ROOT} -GNinja
|
|
||||||
ninja
|
|
||||||
```
|
|
||||||
|
|
||||||
You are now left with `op-finder/op-finder` and `op-finder-tests/op-finder-tests` executables.
|
|
||||||
|
|
||||||
### Usage
|
|
||||||
|
|
||||||
Use `op-finder --help` for help.
|
|
||||||
|
|
||||||
The finder will process multiple source files and output them to a single JSON file. For example:
|
|
||||||
|
|
||||||
`op-finder ./source1.c ./source2.c -o=project_opfinder.json`
|
|
||||||
|
|
||||||
The above line will take the C-code source files of `source1.c` and `source2.c`, extract atomic operations
|
|
||||||
from them, and output the JSON to the `./project_opfinder.json` file. This file can then be given to the
|
|
||||||
analyzer along with a gcov report.
|
|
||||||
|
|
||||||
## Analyzer (Operation Summarizer)
|
|
||||||
|
|
||||||
The Analyzer is responsible for taking the Atomic Operations Finder report and a gcov code coverage report
|
|
||||||
and combining them into a singular analysis of the codebase. In the present implementation, it will
|
|
||||||
summarize all unique atomic operations. This can then be combined with a database of atomic operations
|
|
||||||
and turned into a performance estimation.
|
|
||||||
|
|
||||||
The Analyzer is written in Python and requires no tooling beyond having Python 3 installed. gcov is needed
|
|
||||||
to generate the simulation reports.
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
Install the prerequisites from your package manager:
|
|
||||||
```shell
|
|
||||||
apt update -y
|
|
||||||
apt install gcovr python3 python3-pip
|
|
||||||
pip3 install gcovr
|
|
||||||
```
|
|
||||||
|
|
||||||
### Usage
|
|
||||||
|
|
||||||
Assuming Atomic Operations Parser was used in the previous usage example. The first step is to compile
|
|
||||||
the C program with GCC and to acquire a code coverage report from it using gcovr. This is done as follows:
|
|
||||||
```shell
|
|
||||||
gcc -fprofile-arcs -ftest-coverage -fPIC -O0 ./source1.c ./source2.c -o project.out
|
|
||||||
./project.out
|
|
||||||
gcovr -r ./ --json-pretty -o project_gcov.json
|
|
||||||
```
|
|
||||||
|
|
||||||
This will output the coverage report in human-readable JSON into the `project_gcov.json` file.
|
|
||||||
|
|
||||||
Next, the Analyzer needs to be ran:
|
|
||||||
```shell
|
|
||||||
python3 op-summarizer/opsummarizer.py --gcov project_gcov.json --finder project_opfinder.json --output project_summarized.json source1.c source2.c
|
|
||||||
```
|
|
||||||
|
|
||||||
The list of files in the specifies which source files should be taken into consideration. If a file is not present, then
|
|
||||||
that file will not be evaluated during the summarization.
|
|
||||||
|
|
||||||
The summarizer will then generate an output report in JSON, along with printing a human-readable version out
|
|
||||||
on the screen.
|
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
[requires]
|
|
||||||
catch2/2.13.4
|
|
||||||
nlohmann_json/3.9.1
|
|
||||||
|
|
||||||
[generators]
|
|
||||||
cmake_find_package
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.14)
|
|
||||||
|
|
||||||
find_package(nlohmann_json REQUIRED)
|
|
||||||
find_package(Clang REQUIRED)
|
|
||||||
find_package(LLVM REQUIRED COMPONENTS Support Option Core)
|
|
||||||
|
|
||||||
# LLVM is typically compiled without RTTI. Weird linker errors ensue if
|
|
||||||
# you keep RTTI on and try to link.
|
|
||||||
if (NOT LLVM_ENABLE_RTTI)
|
|
||||||
if (MSVC)
|
|
||||||
string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-")
|
|
||||||
else ()
|
|
||||||
string(REGEX REPLACE "-frtti" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
|
|
||||||
endif ()
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
llvm_map_components_to_libnames(llvm_libs support option core)
|
|
||||||
|
|
||||||
add_library(op-finder-lib STATIC
|
|
||||||
src/OperationFinder.cpp
|
|
||||||
src/OperationStorage.cpp
|
|
||||||
src/OperationAstMatcher.cpp
|
|
||||||
src/OperationFinderAstVisitor.cpp
|
|
||||||
src/OperationFinderAstConsumer.cpp
|
|
||||||
src/OperationFinderAstAction.cpp
|
|
||||||
src/OperationLog.cpp)
|
|
||||||
|
|
||||||
target_include_directories(op-finder-lib
|
|
||||||
PUBLIC
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
|
||||||
${LLVM_INCLUDE_DIRS}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_compile_definitions(op-finder-lib
|
|
||||||
PUBLIC
|
|
||||||
${LLVM_DEFINITIONS}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(op-finder-lib
|
|
||||||
PUBLIC
|
|
||||||
nlohmann_json::nlohmann_json
|
|
||||||
PRIVATE
|
|
||||||
${llvm_libs}
|
|
||||||
clangTooling
|
|
||||||
clangBasic
|
|
||||||
clangASTMatchers
|
|
||||||
)
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 02.03.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef C_ANALYZER_OPERATIONASTMATCHER_HPP
|
|
||||||
#define C_ANALYZER_OPERATIONASTMATCHER_HPP
|
|
||||||
|
|
||||||
#include <clang/ASTMatchers/ASTMatchFinder.h>
|
|
||||||
|
|
||||||
class OperationFinder;
|
|
||||||
|
|
||||||
class OperationASTMatcher : public clang::ast_matchers::MatchFinder::MatchCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit OperationASTMatcher(OperationFinder* finder);
|
|
||||||
|
|
||||||
void addToFinder(clang::ast_matchers::MatchFinder& finder);
|
|
||||||
|
|
||||||
void run(const clang::ast_matchers::MatchFinder::MatchResult& result) override;
|
|
||||||
private:
|
|
||||||
OperationFinder* _op_finder;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //C_ANALYZER_OPERATIONASTMATCHER_HPP
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 16.02.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef LLVM_PROTO_OPERATIONFINDER_HPP
|
|
||||||
#define LLVM_PROTO_OPERATIONFINDER_HPP
|
|
||||||
|
|
||||||
#include <clang/ASTMatchers/ASTMatchFinder.h>
|
|
||||||
|
|
||||||
#include "OperationLog.hpp"
|
|
||||||
|
|
||||||
class OperationFinder
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit OperationFinder(IOperationOutput* storage);
|
|
||||||
|
|
||||||
void processArithmetic(const clang::BinaryOperator* op, const clang::SourceManager& source_manager);
|
|
||||||
void processUnaryArithmetic(const clang::UnaryOperator* op, const clang::SourceManager& source_manager);
|
|
||||||
void processFunctionCall(const clang::CallExpr* call, const clang::SourceManager& source_manager);
|
|
||||||
void processArraySubscript(const clang::ArraySubscriptExpr* subscript, const clang::SourceManager& source_manager);
|
|
||||||
|
|
||||||
void branchEntered();
|
|
||||||
void branchExited();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unique_ptr<OperationLog::BasicOperation>
|
|
||||||
_createBasicOperationLogEntry(const std::string& opcode, const clang::Expr* source, const clang::Expr* op1, const clang::Expr* op2);
|
|
||||||
|
|
||||||
std::pair<std::string, OperationLog> _createBaseOperationLog(const clang::Stmt* stmt, const clang::SourceManager& source_manager);
|
|
||||||
|
|
||||||
int _current_branch = 0;
|
|
||||||
IOperationOutput* _storage;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //LLVM_PROTO_OPERATIONFINDER_HPP
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 02.03.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef C_ANALYZER_OPERATIONFINDERASTACTION_HPP
|
|
||||||
#define C_ANALYZER_OPERATIONFINDERASTACTION_HPP
|
|
||||||
|
|
||||||
#include <clang/Frontend/CompilerInstance.h>
|
|
||||||
#include <clang/Frontend/FrontendActions.h>
|
|
||||||
|
|
||||||
class OperationFinder;
|
|
||||||
|
|
||||||
class OperationFinderAstAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit OperationFinderAstAction(OperationFinder* op_finder);
|
|
||||||
|
|
||||||
std::unique_ptr<clang::ASTConsumer> newASTConsumer();
|
|
||||||
private:
|
|
||||||
OperationFinder* _op_finder;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //C_ANALYZER_OPERATIONFINDERASTACTION_HPP
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 02.03.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef C_ANALYZER_OPERATIONFINDERASTCONSUMER_HPP
|
|
||||||
#define C_ANALYZER_OPERATIONFINDERASTCONSUMER_HPP
|
|
||||||
|
|
||||||
#include <clang/AST/ASTConsumer.h>
|
|
||||||
|
|
||||||
#include "OperationFinderAstVisitor.hpp"
|
|
||||||
|
|
||||||
class OperationFinder;
|
|
||||||
|
|
||||||
class OperationFinderAstConsumer : public clang::ASTConsumer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit OperationFinderAstConsumer(OperationFinder* op_finder);
|
|
||||||
|
|
||||||
void Initialize(clang::ASTContext& context) override;
|
|
||||||
|
|
||||||
void HandleTranslationUnit(clang::ASTContext& context) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
OperationFinderAstVisitor _visitor;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //C_ANALYZER_OPERATIONFINDERASTCONSUMER_HPP
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 02.03.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef C_ANALYZER_OPERATIONFINDERASTVISITOR_HPP
|
|
||||||
#define C_ANALYZER_OPERATIONFINDERASTVISITOR_HPP
|
|
||||||
|
|
||||||
#include <clang/AST/RecursiveASTVisitor.h>
|
|
||||||
|
|
||||||
class OperationFinder;
|
|
||||||
|
|
||||||
class OperationFinderAstVisitor
|
|
||||||
: public clang::RecursiveASTVisitor<OperationFinderAstVisitor>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit OperationFinderAstVisitor(OperationFinder* op_finder);
|
|
||||||
|
|
||||||
void NewContext(clang::ASTContext* context);
|
|
||||||
|
|
||||||
bool VisitForStmt(clang::ForStmt* stmt);
|
|
||||||
bool VisitBinaryOperator(clang::BinaryOperator* op);
|
|
||||||
bool VisitUnaryOperator(clang::UnaryOperator* op);
|
|
||||||
bool VisitCallExpr(clang::CallExpr* call);
|
|
||||||
bool VisitArraySubscriptExpr(clang::ArraySubscriptExpr* subscript);
|
|
||||||
|
|
||||||
bool dataTraverseStmtPre(clang::Stmt* stmt);
|
|
||||||
bool dataTraverseStmtPost(clang::Stmt* stmt);
|
|
||||||
|
|
||||||
private:
|
|
||||||
clang::ASTContext* _context;
|
|
||||||
OperationFinder* _op_finder;
|
|
||||||
|
|
||||||
struct _LoopHeaderStateMachine
|
|
||||||
{
|
|
||||||
bool in_loop_header = false;
|
|
||||||
clang::Stmt* init = nullptr;
|
|
||||||
clang::Stmt* header_start = nullptr;
|
|
||||||
clang::Stmt* header_end = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
_LoopHeaderStateMachine _loop_header;
|
|
||||||
|
|
||||||
std::vector<clang::Stmt*> _branch_stack;
|
|
||||||
|
|
||||||
clang::Stmt* _isBranchEntry(clang::Stmt* stmt);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //C_ANALYZER_OPERATIONFINDERASTVISITOR_HPP
|
|
||||||
@ -1,114 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 28.02.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef C_ANALYZER_OPERATIONLOG_HPP
|
|
||||||
#define C_ANALYZER_OPERATIONLOG_HPP
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <variant>
|
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
struct OperationLog
|
|
||||||
{
|
|
||||||
struct IEntry
|
|
||||||
{
|
|
||||||
[[nodiscard]] virtual nlohmann::json toJson() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FunctionCall : IEntry
|
|
||||||
{
|
|
||||||
static constexpr char TYPE_NAME[] = "function_call";
|
|
||||||
|
|
||||||
std::string function_name;
|
|
||||||
std::string call_result_type;
|
|
||||||
|
|
||||||
[[nodiscard]] nlohmann::json toJson() const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BasicOperation : IEntry
|
|
||||||
{
|
|
||||||
static constexpr char TYPE_NAME[] = "basic_operation";
|
|
||||||
|
|
||||||
std::string operation_name;
|
|
||||||
std::string type_lhs;
|
|
||||||
std::string type_rhs;
|
|
||||||
std::string type_result;
|
|
||||||
|
|
||||||
[[nodiscard]] nlohmann::json toJson() const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
unsigned int line = 0;
|
|
||||||
int branch_number = 0;
|
|
||||||
|
|
||||||
std::string entry_type;
|
|
||||||
std::unique_ptr<IEntry> entry;
|
|
||||||
|
|
||||||
OperationLog() = default;
|
|
||||||
OperationLog(const OperationLog&) = delete;
|
|
||||||
OperationLog(OperationLog&&) = default;
|
|
||||||
|
|
||||||
void DecodeEntry(const nlohmann::json& j);
|
|
||||||
};
|
|
||||||
|
|
||||||
class IOperationOutput
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~IOperationOutput() = default;
|
|
||||||
|
|
||||||
virtual void pushOperation(const std::string& filename, OperationLog&& op) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void to_json(nlohmann::json& j, const OperationLog& l)
|
|
||||||
{
|
|
||||||
j = nlohmann::json{
|
|
||||||
{"line", l.line},
|
|
||||||
{"entry_type", l.entry_type},
|
|
||||||
{"entry", l.entry->toJson()},
|
|
||||||
{"branch_number", l.branch_number}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void from_json(const nlohmann::json& j, OperationLog& l)
|
|
||||||
{
|
|
||||||
j.at("line").get_to(l.line);
|
|
||||||
j.at("entry_type").get_to(l.entry_type);
|
|
||||||
l.DecodeEntry(j["entry"]);
|
|
||||||
|
|
||||||
j.at("branch_number").get_to(l.branch_number);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void to_json(nlohmann::json& j, const OperationLog::BasicOperation& bo)
|
|
||||||
{
|
|
||||||
j = nlohmann::json{
|
|
||||||
{"operation_name", bo.operation_name},
|
|
||||||
{"type_lhs", bo.type_lhs},
|
|
||||||
{"type_rhs", bo.type_rhs},
|
|
||||||
{"type_result", bo.type_result}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void from_json(const nlohmann::json& j, OperationLog::BasicOperation& bo)
|
|
||||||
{
|
|
||||||
j.at("operation_name").get_to(bo.operation_name);
|
|
||||||
j.at("type_lhs").get_to(bo.type_lhs);
|
|
||||||
j.at("type_rhs").get_to(bo.type_rhs);
|
|
||||||
j.at("type_result").get_to(bo.type_result);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void to_json(nlohmann::json& j, const OperationLog::FunctionCall& fcall)
|
|
||||||
{
|
|
||||||
j = nlohmann::json{
|
|
||||||
{"function_name", fcall.function_name},
|
|
||||||
{"call_result_type", fcall.call_result_type}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void from_json(const nlohmann::json& j, OperationLog::FunctionCall& fcall)
|
|
||||||
{
|
|
||||||
j.at("function_name").get_to(fcall.function_name);
|
|
||||||
j.at("call_result_type").get_to(fcall.call_result_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //C_ANALYZER_OPERATIONLOG_HPP
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 28.02.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef C_ANALYZER_OPERATIONSTORAGE_HPP
|
|
||||||
#define C_ANALYZER_OPERATIONSTORAGE_HPP
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "OperationLog.hpp"
|
|
||||||
|
|
||||||
class OperationStorage : public IOperationOutput
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
OperationStorage() = default;
|
|
||||||
OperationStorage(const OperationStorage&) = delete;
|
|
||||||
|
|
||||||
~OperationStorage() override;
|
|
||||||
|
|
||||||
void enablePrettyPrint();
|
|
||||||
void toStream(std::ostream& stream);
|
|
||||||
void toFile(const std::string& output_filename);
|
|
||||||
|
|
||||||
void pushOperation(const std::string& original_filename, OperationLog&& op) override;
|
|
||||||
[[nodiscard]] const std::unordered_map<std::string, std::vector<OperationLog>>& getOperations() const;
|
|
||||||
private:
|
|
||||||
std::unordered_map<std::string, std::vector<OperationLog>> _operations;
|
|
||||||
|
|
||||||
bool _pretty_print = false;
|
|
||||||
|
|
||||||
std::string _convertFilepath(const std::string& original);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //C_ANALYZER_OPERATIONSTORAGE_HPP
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
//src
|
|
||||||
// Created by erki on 02.03.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef C_ANALYZER_ASTHELPERS_HPP
|
|
||||||
#define C_ANALYZER_ASTHELPERS_HPP
|
|
||||||
|
|
||||||
#include <clang/AST/ASTContext.h>
|
|
||||||
|
|
||||||
template<typename TOp>
|
|
||||||
clang::StringRef getOpcode(const TOp *op)
|
|
||||||
{
|
|
||||||
return op->getOpcodeStr(op->getOpcode());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline clang::SourceLocation resolveOperationSourceLocation(const clang::SourceManager& source_manager,
|
|
||||||
const clang::SourceLocation& original)
|
|
||||||
{
|
|
||||||
if (source_manager.isMacroBodyExpansion(original))
|
|
||||||
{
|
|
||||||
return source_manager.getExpansionLoc(original);
|
|
||||||
}
|
|
||||||
|
|
||||||
return original;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::tuple<std::string, unsigned int, unsigned int> resolveLocationsWithLoc(const clang::SourceLocation& loc,
|
|
||||||
const clang::SourceManager& source_manager)
|
|
||||||
{
|
|
||||||
const auto& loc_resolved = resolveOperationSourceLocation(source_manager, loc);
|
|
||||||
|
|
||||||
return {
|
|
||||||
source_manager.getFilename(loc_resolved).str(),
|
|
||||||
source_manager.getSpellingLineNumber(loc_resolved),
|
|
||||||
source_manager.getSpellingColumnNumber(loc_resolved)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename TStmt>
|
|
||||||
std::tuple<std::string, unsigned int, unsigned int> resolveLocations(const TStmt* op,
|
|
||||||
const clang::SourceManager& source_manager)
|
|
||||||
{
|
|
||||||
const auto& loc = resolveOperationSourceLocation(source_manager, op->getBeginLoc());
|
|
||||||
|
|
||||||
return {
|
|
||||||
source_manager.getFilename(loc).str(),
|
|
||||||
source_manager.getSpellingLineNumber(loc),
|
|
||||||
source_manager.getSpellingColumnNumber(loc)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //C_ANALYZER_ASTHELPERS_HPP
|
|
||||||
@ -1,57 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 02.03.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "OperationAstMatcher.hpp"
|
|
||||||
|
|
||||||
#include "OperationFinder.hpp"
|
|
||||||
|
|
||||||
using namespace clang;
|
|
||||||
using namespace clang::ast_matchers;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
StatementMatcher AssignmentMatcher =
|
|
||||||
binaryOperation(isAssignmentOperator(),
|
|
||||||
hasLHS(expr().bind("lhs")),
|
|
||||||
hasRHS(expr().bind("rhs"))).bind("assignment");
|
|
||||||
|
|
||||||
StatementMatcher ArithmeticMatcher =
|
|
||||||
binaryOperation(hasAnyOperatorName("+", "-", "/", "*", "<", ">",
|
|
||||||
"<=", ">=", "==", "<<", ">>", "%"),
|
|
||||||
hasLHS(expr().bind("lhs")),
|
|
||||||
hasRHS(expr().bind("lhs"))).bind("arithmetic");
|
|
||||||
|
|
||||||
StatementMatcher UnaryArithmeticMatcher =
|
|
||||||
unaryOperator(hasAnyOperatorName("!", "++", "--"),
|
|
||||||
hasUnaryOperand(expr().bind("lhs"))).bind("unary_arithmetic");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
OperationASTMatcher::OperationASTMatcher(OperationFinder* finder)
|
|
||||||
: _op_finder(finder)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void OperationASTMatcher::addToFinder(clang::ast_matchers::MatchFinder& finder)
|
|
||||||
{
|
|
||||||
finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, ArithmeticMatcher), this);
|
|
||||||
finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, AssignmentMatcher), this);
|
|
||||||
finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, UnaryArithmeticMatcher), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OperationASTMatcher::run(const clang::ast_matchers::MatchFinder::MatchResult& result)
|
|
||||||
{
|
|
||||||
if (const auto* op = result.Nodes.getNodeAs<clang::BinaryOperator>("assignment"))
|
|
||||||
{
|
|
||||||
_op_finder->processArithmetic(op, *result.SourceManager);
|
|
||||||
}
|
|
||||||
else if (const auto* op = result.Nodes.getNodeAs<clang::BinaryOperator>("arithmetic"))
|
|
||||||
{
|
|
||||||
_op_finder->processArithmetic(op, *result.SourceManager);
|
|
||||||
}
|
|
||||||
else if (const auto* op = result.Nodes.getNodeAs<clang::UnaryOperator>("unary_arithmetic"))
|
|
||||||
{
|
|
||||||
_op_finder->processUnaryArithmetic(op, *result.SourceManager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,170 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 16.02.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "OperationFinder.hpp"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "ASTHelpers.hpp"
|
|
||||||
|
|
||||||
using namespace clang;
|
|
||||||
using namespace clang::ast_matchers;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
std::string ResolveTypeName(const QualType& t)
|
|
||||||
{
|
|
||||||
if (t->isTypedefNameType())
|
|
||||||
{
|
|
||||||
const TypedefType* tdt = cast<TypedefType>(t);
|
|
||||||
assert(tdt);
|
|
||||||
llvm::outs() << "Typedef type: " << t.getAsString()
|
|
||||||
<< ", underlying: " << tdt->desugar().getAsString()
|
|
||||||
<< ".";
|
|
||||||
|
|
||||||
return tdt->desugar().getAsString();
|
|
||||||
}
|
|
||||||
else if (t->isBuiltinType())
|
|
||||||
{
|
|
||||||
llvm::outs() << "Builtin type: " << t.getAsString() << ".";
|
|
||||||
return t.getAsString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
llvm::outs() << "Other type: " << t.getAsString() << ".";
|
|
||||||
return t.getAsString();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
OperationFinder::OperationFinder(IOperationOutput* storage)
|
|
||||||
: _storage(storage)
|
|
||||||
{
|
|
||||||
assert(storage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OperationFinder::processArithmetic(const clang::BinaryOperator* op, const clang::SourceManager& source_manager)
|
|
||||||
{
|
|
||||||
auto [file_name, log] = _createBaseOperationLog(op, source_manager);
|
|
||||||
const std::string op_code = getOpcode(op).str();
|
|
||||||
|
|
||||||
llvm::outs() << "\n\tBinary arithmetic: Type: " << op_code;
|
|
||||||
|
|
||||||
log.entry_type = OperationLog::BasicOperation::TYPE_NAME;
|
|
||||||
log.entry = _createBasicOperationLogEntry(op_code, op, op->getLHS(), op->getRHS());
|
|
||||||
|
|
||||||
_storage->pushOperation(file_name, std::move(log));
|
|
||||||
|
|
||||||
llvm::outs() << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
void OperationFinder::processUnaryArithmetic(const clang::UnaryOperator* op, const clang::SourceManager& source_manager)
|
|
||||||
{
|
|
||||||
auto [file_name, log] = _createBaseOperationLog(op, source_manager);
|
|
||||||
const std::string op_code = getOpcode(op).str();
|
|
||||||
|
|
||||||
llvm::outs() << "\n\tUnary arithmetic: Type: " << op_code;
|
|
||||||
|
|
||||||
log.entry_type = OperationLog::BasicOperation::TYPE_NAME;
|
|
||||||
log.entry = _createBasicOperationLogEntry(op_code, op, op->getExprStmt(), nullptr);
|
|
||||||
|
|
||||||
_storage->pushOperation(file_name, std::move(log));
|
|
||||||
|
|
||||||
llvm::outs() << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
void OperationFinder::processFunctionCall(const clang::CallExpr* call, const SourceManager& source_manager)
|
|
||||||
{
|
|
||||||
const FunctionDecl* func = call->getDirectCallee();
|
|
||||||
|
|
||||||
assert(func);
|
|
||||||
|
|
||||||
auto [file_name, log] = _createBaseOperationLog(call, source_manager);
|
|
||||||
const std::string func_name = func->getNameAsString();
|
|
||||||
|
|
||||||
llvm::outs() << "\n\tFunction call: func name: " << func_name << "\n\tResult eval type: ";
|
|
||||||
|
|
||||||
const std::string res_type = ResolveTypeName(func->getReturnType());
|
|
||||||
|
|
||||||
auto func_call = std::make_unique<OperationLog::FunctionCall>();
|
|
||||||
func_call->function_name = func_name;
|
|
||||||
func_call->call_result_type = res_type;
|
|
||||||
|
|
||||||
log.entry_type = OperationLog::FunctionCall::TYPE_NAME;
|
|
||||||
log.entry = std::move(func_call);
|
|
||||||
|
|
||||||
_storage->pushOperation(file_name, std::move(log));
|
|
||||||
|
|
||||||
llvm::outs() << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
void OperationFinder::processArraySubscript(const clang::ArraySubscriptExpr* subscript, const clang::SourceManager& source_manager)
|
|
||||||
{
|
|
||||||
auto [file_name, log] = _createBaseOperationLog(subscript, source_manager);
|
|
||||||
|
|
||||||
llvm::outs() << "\n\tSubscript:";
|
|
||||||
|
|
||||||
log.entry_type = OperationLog::BasicOperation::TYPE_NAME;
|
|
||||||
log.entry = _createBasicOperationLogEntry("subscript", subscript, subscript->getBase(), subscript->getIdx());
|
|
||||||
|
|
||||||
_storage->pushOperation(file_name, std::move(log));
|
|
||||||
|
|
||||||
llvm::outs() << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
void OperationFinder::branchEntered()
|
|
||||||
{
|
|
||||||
_current_branch++;
|
|
||||||
llvm::outs() << "Branch entered: " << _current_branch << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
void OperationFinder::branchExited()
|
|
||||||
{
|
|
||||||
llvm::outs() << "Branch exited: " << _current_branch << "\n";
|
|
||||||
|
|
||||||
_current_branch--;
|
|
||||||
|
|
||||||
assert(_current_branch > -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<OperationLog::BasicOperation>
|
|
||||||
OperationFinder::_createBasicOperationLogEntry(const std::string& opcode, const Expr* source, const Expr* op1, const Expr* op2)
|
|
||||||
{
|
|
||||||
auto log = std::make_unique<OperationLog::BasicOperation>();
|
|
||||||
|
|
||||||
log->operation_name = opcode;
|
|
||||||
|
|
||||||
llvm::outs() << "\n\tExpression eval type: ";
|
|
||||||
log->type_result = ResolveTypeName(source->getType());
|
|
||||||
|
|
||||||
if (op1)
|
|
||||||
{
|
|
||||||
llvm::outs() << "\n\tLHS eval type: ";
|
|
||||||
log->type_lhs = ResolveTypeName(op1->getType());
|
|
||||||
}
|
|
||||||
if (op2)
|
|
||||||
{
|
|
||||||
llvm::outs() << "\n\tRHS eval type: ";
|
|
||||||
log->type_rhs = ResolveTypeName(op2->getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
return log;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<std::string, OperationLog> OperationFinder::_createBaseOperationLog(const clang::Stmt* stmt, const clang::SourceManager& source_manager)
|
|
||||||
{
|
|
||||||
const auto [file_name, line_number, column_number] = resolveLocations(stmt, source_manager);
|
|
||||||
|
|
||||||
OperationLog log;
|
|
||||||
log.line = line_number;
|
|
||||||
log.branch_number = _current_branch;
|
|
||||||
|
|
||||||
llvm::outs() << file_name << ":"
|
|
||||||
<< line_number << ":"
|
|
||||||
<< column_number << ":";
|
|
||||||
|
|
||||||
return { file_name, std::move(log) };
|
|
||||||
}
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 02.03.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "OperationFinderAstAction.hpp"
|
|
||||||
|
|
||||||
#include "OperationFinderAstConsumer.hpp"
|
|
||||||
|
|
||||||
OperationFinderAstAction::OperationFinderAstAction(OperationFinder* op_finder)
|
|
||||||
: _op_finder(op_finder)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
std::unique_ptr<clang::ASTConsumer> OperationFinderAstAction::newASTConsumer()
|
|
||||||
{
|
|
||||||
return std::unique_ptr<clang::ASTConsumer>(
|
|
||||||
new OperationFinderAstConsumer(_op_finder));
|
|
||||||
}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 02.03.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "OperationFinderAstConsumer.hpp"
|
|
||||||
|
|
||||||
OperationFinderAstConsumer::OperationFinderAstConsumer(OperationFinder* op_finder)
|
|
||||||
: _visitor(op_finder)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void OperationFinderAstConsumer::Initialize(clang::ASTContext& context)
|
|
||||||
{
|
|
||||||
_visitor.NewContext(&context);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OperationFinderAstConsumer::HandleTranslationUnit(clang::ASTContext& context)
|
|
||||||
{
|
|
||||||
_visitor.TraverseAST(context);
|
|
||||||
}
|
|
||||||
@ -1,154 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 02.03.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "OperationFinderAstVisitor.hpp"
|
|
||||||
|
|
||||||
#include "OperationFinder.hpp"
|
|
||||||
#include "ASTHelpers.hpp"
|
|
||||||
|
|
||||||
OperationFinderAstVisitor::OperationFinderAstVisitor(OperationFinder* op_finder)
|
|
||||||
: _context(nullptr)
|
|
||||||
, _op_finder(op_finder)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void OperationFinderAstVisitor::NewContext(clang::ASTContext* context)
|
|
||||||
{
|
|
||||||
_context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OperationFinderAstVisitor::VisitForStmt(clang::ForStmt* stmt)
|
|
||||||
{
|
|
||||||
assert(_context);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OperationFinderAstVisitor::VisitBinaryOperator(clang::BinaryOperator* op)
|
|
||||||
{
|
|
||||||
assert(_context);
|
|
||||||
|
|
||||||
_op_finder->processArithmetic(op, _context->getSourceManager());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OperationFinderAstVisitor::VisitUnaryOperator(clang::UnaryOperator* op)
|
|
||||||
{
|
|
||||||
assert(_context);
|
|
||||||
|
|
||||||
_op_finder->processUnaryArithmetic(op, _context->getSourceManager());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OperationFinderAstVisitor::VisitCallExpr(clang::CallExpr* call)
|
|
||||||
{
|
|
||||||
assert(_context);
|
|
||||||
|
|
||||||
_op_finder->processFunctionCall(call, _context->getSourceManager());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OperationFinderAstVisitor::VisitArraySubscriptExpr(clang::ArraySubscriptExpr* subscript)
|
|
||||||
{
|
|
||||||
assert(_context);
|
|
||||||
|
|
||||||
_op_finder->processArraySubscript(subscript, _context->getSourceManager());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OperationFinderAstVisitor::dataTraverseStmtPre(clang::Stmt* stmt)
|
|
||||||
{
|
|
||||||
assert(_context);
|
|
||||||
|
|
||||||
if (clang::Stmt* branch_entry = _isBranchEntry(stmt))
|
|
||||||
{
|
|
||||||
_branch_stack.push_back(branch_entry);
|
|
||||||
_op_finder->branchEntered();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OperationFinderAstVisitor::dataTraverseStmtPost(clang::Stmt* stmt)
|
|
||||||
{
|
|
||||||
assert(_context);
|
|
||||||
|
|
||||||
if (_loop_header.in_loop_header && (_loop_header.init == stmt || _loop_header.header_end == stmt))
|
|
||||||
{
|
|
||||||
if (_loop_header.header_end == stmt)
|
|
||||||
{
|
|
||||||
assert(_branch_stack.back() == stmt);
|
|
||||||
_branch_stack.pop_back();
|
|
||||||
_op_finder->branchExited();
|
|
||||||
|
|
||||||
if (_loop_header.init)
|
|
||||||
{
|
|
||||||
assert(_branch_stack.back() == _loop_header.init);
|
|
||||||
_branch_stack.pop_back();
|
|
||||||
_op_finder->branchExited();
|
|
||||||
}
|
|
||||||
|
|
||||||
_loop_header = {};
|
|
||||||
}
|
|
||||||
else if (_loop_header.init == stmt && !_loop_header.header_end)
|
|
||||||
{
|
|
||||||
assert(_branch_stack.back() == stmt);
|
|
||||||
_branch_stack.pop_back();
|
|
||||||
_op_finder->branchExited();
|
|
||||||
|
|
||||||
_loop_header = {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!_branch_stack.empty() && _branch_stack.back() == stmt)
|
|
||||||
{
|
|
||||||
_branch_stack.pop_back();
|
|
||||||
_op_finder->branchExited();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assert(std::find(_branch_stack.cbegin(), _branch_stack.cend(), stmt)
|
|
||||||
== _branch_stack.cend());
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
clang::Stmt* OperationFinderAstVisitor::_isBranchEntry(clang::Stmt* stmt)
|
|
||||||
{
|
|
||||||
if (auto* loop = clang::dyn_cast<clang::ForStmt>(stmt);
|
|
||||||
loop && loop->getInit() && (loop->getInc() || loop->getCond()))
|
|
||||||
{
|
|
||||||
_loop_header.init = loop->getInit();
|
|
||||||
|
|
||||||
if (loop->getCond())
|
|
||||||
{
|
|
||||||
_loop_header.header_start = loop->getCond();
|
|
||||||
_loop_header.header_end = loop->getCond();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loop->getInc())
|
|
||||||
{
|
|
||||||
if (!_loop_header.header_start)
|
|
||||||
_loop_header.header_start = loop->getInc();
|
|
||||||
|
|
||||||
_loop_header.header_end = loop->getInc();
|
|
||||||
}
|
|
||||||
|
|
||||||
_loop_header.in_loop_header = _loop_header.init || _loop_header.header_end;
|
|
||||||
|
|
||||||
if (_loop_header.init)
|
|
||||||
return _loop_header.init;
|
|
||||||
else if (_loop_header.header_start)
|
|
||||||
return _loop_header.header_end;
|
|
||||||
}
|
|
||||||
else if (_loop_header.in_loop_header && _loop_header.header_start == stmt)
|
|
||||||
{
|
|
||||||
return _loop_header.header_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 06.03.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "OperationLog.hpp"
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
std::unique_ptr<T> DecodeType(const nlohmann::json& j, const std::string& entry_type)
|
|
||||||
{
|
|
||||||
if (entry_type == T::TYPE_NAME)
|
|
||||||
{
|
|
||||||
auto t = std::make_unique<T>();
|
|
||||||
j.get_to(*t);
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
nlohmann::json OperationLog::FunctionCall::toJson() const
|
|
||||||
{
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
nlohmann::json OperationLog::BasicOperation::toJson() const
|
|
||||||
{
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OperationLog::DecodeEntry(const nlohmann::json& j)
|
|
||||||
{
|
|
||||||
if ((entry = DecodeType<BasicOperation>(j, entry_type)))
|
|
||||||
return;
|
|
||||||
else if ((entry = DecodeType<FunctionCall>(j, entry_type)))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 28.02.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "OperationStorage.hpp"
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
#include <llvm/Support/CommandLine.h>
|
|
||||||
|
|
||||||
OperationStorage::~OperationStorage()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void OperationStorage::enablePrettyPrint()
|
|
||||||
{
|
|
||||||
_pretty_print = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OperationStorage::toStream(std::ostream& stream)
|
|
||||||
{
|
|
||||||
nlohmann::json json = _operations;
|
|
||||||
|
|
||||||
if (_pretty_print)
|
|
||||||
stream << std::setw(4) << json;
|
|
||||||
else
|
|
||||||
stream << json;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OperationStorage::toFile(const std::string& output_filename)
|
|
||||||
{
|
|
||||||
std::ofstream file(output_filename);
|
|
||||||
|
|
||||||
toStream(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void OperationStorage::pushOperation(const std::string& original_filename, OperationLog&& op)
|
|
||||||
{
|
|
||||||
const std::string filename = _convertFilepath(original_filename);
|
|
||||||
auto it = _operations.find(filename);
|
|
||||||
|
|
||||||
if (it == _operations.end())
|
|
||||||
it = _operations.emplace(filename, std::vector<OperationLog>()).first;
|
|
||||||
|
|
||||||
it->second.emplace_back(std::move(op));
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::unordered_map<std::string, std::vector<OperationLog>>& OperationStorage::getOperations() const
|
|
||||||
{
|
|
||||||
return _operations;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string OperationStorage::_convertFilepath(const std::string& original)
|
|
||||||
{
|
|
||||||
const std::filesystem::path path = original;
|
|
||||||
|
|
||||||
return path.filename().string();
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.14)
|
|
||||||
|
|
||||||
find_package(Catch2 REQUIRED)
|
|
||||||
|
|
||||||
# LLVM is typically compiled without RTTI. Weird linker errors ensue if
|
|
||||||
# you keep RTTI on and try to link.
|
|
||||||
if (NOT LLVM_ENABLE_RTTI)
|
|
||||||
if (MSVC)
|
|
||||||
string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-")
|
|
||||||
else ()
|
|
||||||
string(REGEX REPLACE "-frtti" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
|
|
||||||
endif ()
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
add_executable(op-finder-tests
|
|
||||||
main.cpp
|
|
||||||
fixtures/RunOnCodeFixture.cpp
|
|
||||||
basic_operations.cpp
|
|
||||||
branches.cpp
|
|
||||||
function_calls.cpp)
|
|
||||||
|
|
||||||
target_link_libraries(op-finder-tests
|
|
||||||
PUBLIC
|
|
||||||
op-finder-lib
|
|
||||||
Catch2::Catch2)
|
|
||||||
|
|
||||||
include(CTest)
|
|
||||||
include(Catch)
|
|
||||||
catch_discover_tests(op-finder-tests)
|
|
||||||
@ -1,95 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 07.03.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <catch2/catch.hpp>
|
|
||||||
|
|
||||||
#include "fixtures/RunOnCodeFixture.hpp"
|
|
||||||
|
|
||||||
TEST_CASE("Finds binary operations", "[basic_operation]")
|
|
||||||
{
|
|
||||||
auto binary_operand = GENERATE(std::string("="), std::string("+"), std::string("-"), std::string("/"),
|
|
||||||
std::string("*"), std::string("<<"), std::string(">>"),
|
|
||||||
std::string("^"), std::string("=="), std::string("|"), std::string("&"));
|
|
||||||
RunOnCodeFixture fixture;
|
|
||||||
|
|
||||||
const std::string code = "int main() { int a; (void)(a " + binary_operand + " 4); }";
|
|
||||||
const auto& operations = fixture(code);
|
|
||||||
|
|
||||||
REQUIRE(operations.size() == 1);
|
|
||||||
|
|
||||||
const OperationLog& log = operations.front();
|
|
||||||
|
|
||||||
REQUIRE(log.entry_type == OperationLog::BasicOperation::TYPE_NAME);
|
|
||||||
|
|
||||||
const OperationLog::BasicOperation* op = (OperationLog::BasicOperation*)(log.entry.get());
|
|
||||||
|
|
||||||
REQUIRE(op->operation_name == binary_operand);
|
|
||||||
REQUIRE(op->type_lhs == "int");
|
|
||||||
REQUIRE(op->type_rhs == "int");
|
|
||||||
REQUIRE(op->type_result == "int");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Find unary operations", "[basic_operation]")
|
|
||||||
{
|
|
||||||
auto unary_operand = GENERATE(std::string("++"), std::string("--"), std::string("~"), std::string("!"));
|
|
||||||
RunOnCodeFixture fixture;
|
|
||||||
|
|
||||||
const std::string code = "int main() { int a; (void)(" + unary_operand + "a); }";
|
|
||||||
const auto& operations = fixture(code);
|
|
||||||
|
|
||||||
REQUIRE(operations.size() == 1);
|
|
||||||
|
|
||||||
const OperationLog& log = operations.front();
|
|
||||||
|
|
||||||
REQUIRE(log.entry_type == OperationLog::BasicOperation::TYPE_NAME);
|
|
||||||
|
|
||||||
const OperationLog::BasicOperation* op = (OperationLog::BasicOperation*)(log.entry.get());
|
|
||||||
|
|
||||||
REQUIRE(op->operation_name == unary_operand);
|
|
||||||
REQUIRE(op->type_lhs == "int");
|
|
||||||
REQUIRE(op->type_rhs.empty());
|
|
||||||
REQUIRE(op->type_result == "int");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Find subscript operation", "[basic_operation]")
|
|
||||||
{
|
|
||||||
RunOnCodeFixture fixture;
|
|
||||||
|
|
||||||
const std::string code = "int main() { int a[4]; (void)a[4]; }";
|
|
||||||
const auto& operations = fixture(code);
|
|
||||||
|
|
||||||
REQUIRE(operations.size() == 1);
|
|
||||||
|
|
||||||
const OperationLog& log = operations.front();
|
|
||||||
|
|
||||||
REQUIRE(log.entry_type == OperationLog::BasicOperation::TYPE_NAME);
|
|
||||||
|
|
||||||
const OperationLog::BasicOperation* op = (OperationLog::BasicOperation*)(log.entry.get());
|
|
||||||
|
|
||||||
REQUIRE(op->operation_name == "subscript");
|
|
||||||
REQUIRE(op->type_lhs == "int *");
|
|
||||||
REQUIRE(op->type_rhs == "int");
|
|
||||||
REQUIRE(op->type_result == "int");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Find subscript operation reversed", "[basic_operation]")
|
|
||||||
{
|
|
||||||
RunOnCodeFixture fixture;
|
|
||||||
|
|
||||||
const std::string code = "int main() { int a[4]; (void)4[a]; }";
|
|
||||||
const auto& operations = fixture(code);
|
|
||||||
|
|
||||||
REQUIRE(operations.size() == 1);
|
|
||||||
|
|
||||||
const OperationLog& log = operations.front();
|
|
||||||
|
|
||||||
REQUIRE(log.entry_type == OperationLog::BasicOperation::TYPE_NAME);
|
|
||||||
|
|
||||||
const OperationLog::BasicOperation* op = (OperationLog::BasicOperation*)(log.entry.get());
|
|
||||||
|
|
||||||
REQUIRE(op->operation_name == "subscript");
|
|
||||||
REQUIRE(op->type_lhs == "int *");
|
|
||||||
REQUIRE(op->type_rhs == "int");
|
|
||||||
REQUIRE(op->type_result == "int");
|
|
||||||
}
|
|
||||||
@ -1,125 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 07.03.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <catch2/catch.hpp>
|
|
||||||
|
|
||||||
#include "fixtures/RunOnCodeFixture.hpp"
|
|
||||||
|
|
||||||
TEST_CASE("For loop without header.", "[branches][for_loops]")
|
|
||||||
{
|
|
||||||
RunOnCodeFixture fixture;
|
|
||||||
|
|
||||||
const std::string code = "int main() { int a; for (;;) {} }";
|
|
||||||
REQUIRE(fixture.runCode(code));
|
|
||||||
|
|
||||||
REQUIRE(fixture.storage.getOperations().empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("For loop with init only.", "[branches][for_loops]")
|
|
||||||
{
|
|
||||||
RunOnCodeFixture fixture;
|
|
||||||
|
|
||||||
const std::string code = "int main() { int a; for (a = 4;;) {} }";
|
|
||||||
const auto& operations = fixture(code);
|
|
||||||
|
|
||||||
REQUIRE(operations.size() == 1);
|
|
||||||
|
|
||||||
const OperationLog& log = operations.front();
|
|
||||||
|
|
||||||
REQUIRE(log.branch_number == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("For loop with init & cond.", "[branches][for_loops]")
|
|
||||||
{
|
|
||||||
RunOnCodeFixture fixture;
|
|
||||||
|
|
||||||
const std::string code = "int main() { int a; for (a = 4; a < 4;) {} }";
|
|
||||||
const auto& operations = fixture(code);
|
|
||||||
|
|
||||||
REQUIRE(operations.size() == 2);
|
|
||||||
|
|
||||||
const OperationLog& log_init = operations.at(0);
|
|
||||||
REQUIRE(log_init.branch_number == 1);
|
|
||||||
|
|
||||||
const OperationLog& log_cond = operations.at(1);
|
|
||||||
REQUIRE(log_cond.branch_number == 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("For loop with init & inc.", "[branches][for_loops]")
|
|
||||||
{
|
|
||||||
RunOnCodeFixture fixture;
|
|
||||||
|
|
||||||
const std::string code = "int main() { int a; for (a = 4;;a++) {} }";
|
|
||||||
const auto& operations = fixture(code);
|
|
||||||
|
|
||||||
REQUIRE(operations.size() == 2);
|
|
||||||
|
|
||||||
const OperationLog& log_init = operations.at(0);
|
|
||||||
REQUIRE(log_init.branch_number == 1);
|
|
||||||
|
|
||||||
const OperationLog& log_inc = operations.at(1);
|
|
||||||
REQUIRE(log_inc.branch_number == 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("For loop with full header.", "[branches][for_loops]")
|
|
||||||
{
|
|
||||||
RunOnCodeFixture fixture;
|
|
||||||
|
|
||||||
const std::string code = "int main() { int a; for (a = 4; a < 4 ;a++) {} }";
|
|
||||||
const auto& operations = fixture(code);
|
|
||||||
|
|
||||||
REQUIRE(operations.size() == 3);
|
|
||||||
|
|
||||||
const OperationLog& log_init = operations.at(0);
|
|
||||||
REQUIRE(log_init.branch_number == 1);
|
|
||||||
|
|
||||||
const OperationLog& log_cond = operations.at(1);
|
|
||||||
REQUIRE(log_cond.branch_number == 2);
|
|
||||||
|
|
||||||
const OperationLog& log_inc = operations.at(2);
|
|
||||||
REQUIRE(log_inc.branch_number == 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("For loop without init.", "[branches][for_loops]")
|
|
||||||
{
|
|
||||||
RunOnCodeFixture fixture;
|
|
||||||
|
|
||||||
const std::string code = "int main() { int a; for (;a < 4 ;a++) {} }";
|
|
||||||
const auto& operations = fixture(code);
|
|
||||||
|
|
||||||
REQUIRE(operations.size() == 2);
|
|
||||||
|
|
||||||
const OperationLog& log_cond = operations.at(0);
|
|
||||||
REQUIRE(log_cond.branch_number == 0);
|
|
||||||
|
|
||||||
const OperationLog& log_inc = operations.at(1);
|
|
||||||
REQUIRE(log_inc.branch_number == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("For loop closes branches inside the loop.", "[branches][for_loops]")
|
|
||||||
{
|
|
||||||
RunOnCodeFixture fixture;
|
|
||||||
|
|
||||||
const std::string code = "int main() { int a; for (a = 4; a < 4 ; a++) { a = 5; } }";
|
|
||||||
const auto& operations = fixture(code);
|
|
||||||
|
|
||||||
REQUIRE(operations.size() == 4);
|
|
||||||
|
|
||||||
const OperationLog& log_inner = operations.back();
|
|
||||||
REQUIRE(log_inner.branch_number == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("For loop closes branches outside the loop.", "[branches][for_loops]")
|
|
||||||
{
|
|
||||||
RunOnCodeFixture fixture;
|
|
||||||
|
|
||||||
const std::string code = "int main() { int a; for (a = 4; a < 4 ; a++) {} a = 5; }";
|
|
||||||
const auto& operations = fixture(code);
|
|
||||||
|
|
||||||
REQUIRE(operations.size() == 4);
|
|
||||||
|
|
||||||
const OperationLog& log_outer = operations.back();
|
|
||||||
REQUIRE(log_outer.branch_number == 0);
|
|
||||||
}
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 07.03.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "RunOnCodeFixture.hpp"
|
|
||||||
|
|
||||||
#include <catch2/catch.hpp>
|
|
||||||
|
|
||||||
#include <clang/Tooling/Tooling.h>
|
|
||||||
#include <clang/Frontend/FrontendActions.h>
|
|
||||||
|
|
||||||
RunOnCodeFixture::RunOnCodeFixture()
|
|
||||||
: finder(&storage)
|
|
||||||
, action(&finder)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
bool RunOnCodeFixture::runCode(const std::string& code)
|
|
||||||
{
|
|
||||||
return clang::tooling::runToolOnCode(
|
|
||||||
clang::tooling::newFrontendActionFactory(&action)->create(),
|
|
||||||
code,
|
|
||||||
RunOnCodeFixture::INPUT_FILE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<OperationLog>& RunOnCodeFixture::operator()(const std::string& code)
|
|
||||||
{
|
|
||||||
const bool success = runCode(code);
|
|
||||||
|
|
||||||
REQUIRE(success);
|
|
||||||
|
|
||||||
const auto& operations = storage.getOperations();
|
|
||||||
|
|
||||||
REQUIRE(operations.count(RunOnCodeFixture::INPUT_FILE) == 1);
|
|
||||||
|
|
||||||
return operations.at(RunOnCodeFixture::INPUT_FILE);
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 07.03.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef C_ANALYZER_RUNONCODEFIXTURE_HPP
|
|
||||||
#define C_ANALYZER_RUNONCODEFIXTURE_HPP
|
|
||||||
|
|
||||||
#include <OperationStorage.hpp>
|
|
||||||
#include <OperationFinder.hpp>
|
|
||||||
#include <OperationFinderAstAction.hpp>
|
|
||||||
|
|
||||||
struct RunOnCodeFixture
|
|
||||||
{
|
|
||||||
constexpr static char INPUT_FILE[] = "input.c";
|
|
||||||
|
|
||||||
OperationStorage storage;
|
|
||||||
OperationFinder finder;
|
|
||||||
OperationFinderAstAction action;
|
|
||||||
|
|
||||||
RunOnCodeFixture();
|
|
||||||
|
|
||||||
bool runCode(const std::string& code);
|
|
||||||
|
|
||||||
const std::vector<OperationLog>& operator()(const std::string& code);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //C_ANALYZER_RUNONCODEFIXTURE_HPP
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 07.03.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <catch2/catch.hpp>
|
|
||||||
|
|
||||||
#include "fixtures/RunOnCodeFixture.hpp"
|
|
||||||
|
|
||||||
TEST_CASE("Find function call.", "[functions]")
|
|
||||||
{
|
|
||||||
RunOnCodeFixture fixture;
|
|
||||||
|
|
||||||
const std::string code = "int b(); int main() { b(); }";
|
|
||||||
const auto& operations = fixture(code);
|
|
||||||
|
|
||||||
REQUIRE(operations.size() == 1);
|
|
||||||
|
|
||||||
const OperationLog& log = operations.front();
|
|
||||||
|
|
||||||
REQUIRE(log.entry_type == OperationLog::FunctionCall::TYPE_NAME);
|
|
||||||
|
|
||||||
const OperationLog::FunctionCall* call = (OperationLog::FunctionCall*)log.entry.get();
|
|
||||||
|
|
||||||
REQUIRE(call->function_name == "b");
|
|
||||||
REQUIRE(call->call_result_type == "int");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Find stacked function calls.", "[functions]")
|
|
||||||
{
|
|
||||||
RunOnCodeFixture fixture;
|
|
||||||
|
|
||||||
const std::string code = "int a(int); int b(); int main() { a(b()); }";
|
|
||||||
const auto& operations = fixture(code);
|
|
||||||
|
|
||||||
REQUIRE(operations.size() == 2);
|
|
||||||
|
|
||||||
const OperationLog& log = operations.front();
|
|
||||||
|
|
||||||
REQUIRE(log.entry_type == OperationLog::FunctionCall::TYPE_NAME);
|
|
||||||
|
|
||||||
const OperationLog::FunctionCall* call = (OperationLog::FunctionCall*)log.entry.get();
|
|
||||||
|
|
||||||
REQUIRE(call->function_name == "a");
|
|
||||||
REQUIRE(call->call_result_type == "int");
|
|
||||||
|
|
||||||
|
|
||||||
const OperationLog& log_two = operations.back();
|
|
||||||
|
|
||||||
REQUIRE(log_two.entry_type == OperationLog::FunctionCall::TYPE_NAME);
|
|
||||||
|
|
||||||
const OperationLog::FunctionCall* call_two = (OperationLog::FunctionCall*)log_two.entry.get();
|
|
||||||
|
|
||||||
REQUIRE(call_two->function_name == "b");
|
|
||||||
REQUIRE(call_two->call_result_type == "int");
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by erki on 07.03.21.
|
|
||||||
//
|
|
||||||
|
|
||||||
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
|
|
||||||
#include <catch2/catch.hpp>
|
|
||||||
@ -1,4 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.14)
|
cmake_minimum_required(VERSION 3.17)
|
||||||
|
|
||||||
|
find_package(Clang REQUIRED)
|
||||||
|
find_package(LLVM REQUIRED COMPONENTS Support Option Core)
|
||||||
|
|
||||||
# LLVM is typically compiled without RTTI. Weird linker errors ensue if
|
# LLVM is typically compiled without RTTI. Weird linker errors ensue if
|
||||||
# you keep RTTI on and try to link.
|
# you keep RTTI on and try to link.
|
||||||
@ -12,9 +15,29 @@ if (NOT LLVM_ENABLE_RTTI)
|
|||||||
endif ()
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
llvm_map_components_to_libnames(llvm_libs support option core)
|
||||||
|
|
||||||
add_executable(op-finder
|
add_executable(op-finder
|
||||||
main.cpp)
|
main.cpp
|
||||||
|
OperationFinder.cpp
|
||||||
|
OperationFinderConsumer.cpp
|
||||||
|
OperationFinderAction.cpp
|
||||||
|
OperationAnalyzer.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(op-finder
|
||||||
|
PRIVATE ${LLVM_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(op-finder
|
||||||
|
PRIVATE
|
||||||
|
${LLVM_DEFINITIONS}
|
||||||
|
)
|
||||||
|
|
||||||
target_link_libraries(op-finder
|
target_link_libraries(op-finder
|
||||||
PUBLIC
|
PRIVATE
|
||||||
op-finder-lib)
|
${llvm_libs}
|
||||||
|
clangTooling
|
||||||
|
clangBasic
|
||||||
|
clangASTMatchers
|
||||||
|
)
|
||||||
|
|||||||
135
op-finder/OperationAnalyzer.cpp
Normal file
135
op-finder/OperationAnalyzer.cpp
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 24.02.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "OperationAnalyzer.hpp"
|
||||||
|
|
||||||
|
#include <clang/Basic/SourceManager.h>
|
||||||
|
|
||||||
|
using namespace clang;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
bool IsInMainFile(const SourceManager& source_manager, const SourceLocation& loc)
|
||||||
|
{
|
||||||
|
//return source_manager.isWrittenInMainFile(loc);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TOp>
|
||||||
|
StringRef getOpcode(const TOp *op)
|
||||||
|
{
|
||||||
|
return op->getOpcodeStr(op->getOpcode());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperationAnalyzer::processAssignment(const BinaryOperator* op, const SourceManager& source_manager)
|
||||||
|
{
|
||||||
|
if (!IsInMainFile(source_manager, op->getBeginLoc()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto& loc = op->getBeginLoc();
|
||||||
|
|
||||||
|
|
||||||
|
llvm::outs() << source_manager.getFilename(loc) << ":"
|
||||||
|
<< source_manager.getSpellingLineNumber(loc) << ":"
|
||||||
|
<< source_manager.getSpellingColumnNumber(loc) << ":"
|
||||||
|
<< "Assignment: Assigned to: ";
|
||||||
|
|
||||||
|
_processExpressionTypes(op, op->getLHS(), op->getRHS());
|
||||||
|
|
||||||
|
llvm::outs() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperationAnalyzer::processBinaryArithmetic(const BinaryOperator* op, const SourceManager& source_manager)
|
||||||
|
{
|
||||||
|
if (!IsInMainFile(source_manager, op->getBeginLoc()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto& loc = op->getBeginLoc();
|
||||||
|
|
||||||
|
llvm::outs() << source_manager.getFilename(loc) << ":"
|
||||||
|
<< source_manager.getSpellingLineNumber(loc) << ":"
|
||||||
|
<< source_manager.getSpellingColumnNumber(loc) << ":"
|
||||||
|
<< "Arithmetic: Type: " << getOpcode(op) << " LHS: ";
|
||||||
|
|
||||||
|
_processExpressionTypes(op, op->getLHS(), op->getRHS());
|
||||||
|
|
||||||
|
llvm::outs() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperationAnalyzer::processCompoundAssignment(const clang::CompoundAssignOperator* op, const SourceManager& source_manager)
|
||||||
|
{
|
||||||
|
if (!IsInMainFile(source_manager, op->getBeginLoc()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto& loc = op->getBeginLoc();
|
||||||
|
|
||||||
|
llvm::outs() << source_manager.getFilename(loc) << ":"
|
||||||
|
<< source_manager.getSpellingLineNumber(loc) << ":"
|
||||||
|
<< source_manager.getSpellingColumnNumber(loc) << ":"
|
||||||
|
<< "Compound assignment: Op code: " << getOpcode(op) << " ";
|
||||||
|
|
||||||
|
_processExpressionTypes(op, op->getLHS(), op->getRHS());
|
||||||
|
|
||||||
|
llvm::outs() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperationAnalyzer::processUnaryArithmetic(const UnaryOperator* op, const SourceManager& source_manager)
|
||||||
|
{
|
||||||
|
const Expr* lhs = op->getExprStmt();
|
||||||
|
|
||||||
|
if (!IsInMainFile(source_manager, lhs->getBeginLoc()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto& loc = lhs->getBeginLoc();
|
||||||
|
|
||||||
|
llvm::outs() << source_manager.getFilename(loc) << ":"
|
||||||
|
<< source_manager.getSpellingLineNumber(loc) << ":"
|
||||||
|
<< source_manager.getSpellingColumnNumber(loc) << ":"
|
||||||
|
<< "Unary arithmetic: Type: " << getOpcode(op) << " LHS: ";
|
||||||
|
|
||||||
|
_processExpressionTypes(op, lhs, nullptr);
|
||||||
|
|
||||||
|
llvm::outs() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperationAnalyzer::_processExpressionTypes(const Expr* source, const Expr* lhs,
|
||||||
|
const Expr* rhs)
|
||||||
|
{
|
||||||
|
auto printTypeName = [](const QualType& t) -> void
|
||||||
|
{
|
||||||
|
if (t->isTypedefNameType())
|
||||||
|
{
|
||||||
|
const TypedefType* tdt = cast<TypedefType>(t);
|
||||||
|
assert(tdt);
|
||||||
|
llvm::outs() << "Typedef type: " << t.getAsString()
|
||||||
|
<< ", underlying: " << tdt->desugar().getAsString()
|
||||||
|
<< ".";
|
||||||
|
}
|
||||||
|
else if (t->isBuiltinType())
|
||||||
|
{
|
||||||
|
llvm::outs() << "Builtin type: " << t.getAsString() << ".";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
llvm::outs() << "Other type: " << t.getAsString() << ".";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
llvm::outs() << "Expression types:\n\tExpression eval type: ";
|
||||||
|
printTypeName(source->getType());
|
||||||
|
|
||||||
|
if (lhs)
|
||||||
|
{
|
||||||
|
llvm::outs() << "\n\tLHS eval type: ";
|
||||||
|
printTypeName(lhs->getType());
|
||||||
|
}
|
||||||
|
if (rhs)
|
||||||
|
{
|
||||||
|
llvm::outs() << "\n\tRHS eval type: ";
|
||||||
|
printTypeName(rhs->getType());
|
||||||
|
}
|
||||||
|
}
|
||||||
23
op-finder/OperationAnalyzer.hpp
Normal file
23
op-finder/OperationAnalyzer.hpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 24.02.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef C_ANALYZER_OPERATIONANALYZER_HPP
|
||||||
|
#define C_ANALYZER_OPERATIONANALYZER_HPP
|
||||||
|
|
||||||
|
#include <clang/AST/AST.h>
|
||||||
|
|
||||||
|
class OperationAnalyzer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void processAssignment(const clang::BinaryOperator* op, const clang::SourceManager& source_manager);
|
||||||
|
void processBinaryArithmetic(const clang::BinaryOperator* op, const clang::SourceManager& source_manager);
|
||||||
|
void processCompoundAssignment(const clang::CompoundAssignOperator* op, const clang::SourceManager& source_manager);
|
||||||
|
void processUnaryArithmetic(const clang::UnaryOperator* op, const clang::SourceManager& source_manager);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _processExpressionTypes(const clang::Expr* source, const clang::Expr* lhs, const clang::Expr* rhs);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //C_ANALYZER_OPERATIONANALYZER_HPP
|
||||||
114
op-finder/OperationFinder.cpp
Normal file
114
op-finder/OperationFinder.cpp
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 16.02.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "OperationFinder.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
using namespace clang;
|
||||||
|
using namespace clang::ast_matchers;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
StatementMatcher AssignmentMatcher =
|
||||||
|
binaryOperation(isAssignmentOperator(),
|
||||||
|
hasLHS(expr().bind("lhs")),
|
||||||
|
hasRHS(expr().bind("rhs"))).bind("assignment");
|
||||||
|
|
||||||
|
StatementMatcher ArithmeticMatcher =
|
||||||
|
binaryOperation(hasAnyOperatorName("+", "-", "/", "*", "<", ">",
|
||||||
|
"<=", ">=", "==", "<<", ">>", "%"),
|
||||||
|
hasLHS(expr().bind("lhs")),
|
||||||
|
hasRHS(expr().bind("lhs"))).bind("arithmetic");
|
||||||
|
|
||||||
|
StatementMatcher UnaryArithmeticMatcher =
|
||||||
|
unaryOperator(hasAnyOperatorName("!", "++", "--"),
|
||||||
|
hasUnaryOperand(expr().bind("lhs"))).bind("unary_arithmetic");
|
||||||
|
|
||||||
|
StatementMatcher CompoundMatcher =
|
||||||
|
compoundStmt().bind("compound_stmt");
|
||||||
|
|
||||||
|
bool isInMainFile(const MatchFinder::MatchResult &result, const SourceLocation &loc)
|
||||||
|
{
|
||||||
|
return result.Context->getSourceManager().isWrittenInMainFile(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TOp>
|
||||||
|
StringRef getOpcode(const TOp *op)
|
||||||
|
{
|
||||||
|
return op->getOpcodeStr(op->getOpcode());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperationFinder::addMatcher(MatchFinder &finder)
|
||||||
|
{
|
||||||
|
finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, ArithmeticMatcher), this);
|
||||||
|
finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, AssignmentMatcher), this);
|
||||||
|
finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, CompoundMatcher), this);
|
||||||
|
finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, UnaryArithmeticMatcher), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperationFinder::run(const MatchFinder::MatchResult &result)
|
||||||
|
{
|
||||||
|
if (result.Nodes.getNodeAs<clang::BinaryOperator>("assignment"))
|
||||||
|
{
|
||||||
|
_processAssignment(result);
|
||||||
|
}
|
||||||
|
else if (result.Nodes.getNodeAs<clang::BinaryOperator>("arithmetic"))
|
||||||
|
{
|
||||||
|
_processArithmetic(result);
|
||||||
|
}
|
||||||
|
else if (result.Nodes.getNodeAs<clang::CompoundStmt>("compound_stmt"))
|
||||||
|
{
|
||||||
|
_processCompoundStmt(result);
|
||||||
|
}
|
||||||
|
else if (result.Nodes.getNodeAs<clang::UnaryOperator>("unary_arithmetic"))
|
||||||
|
{
|
||||||
|
_processUnaryArithmetic(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperationFinder::_processAssignment(const clang::ast_matchers::MatchFinder::MatchResult& result)
|
||||||
|
{
|
||||||
|
const BinaryOperator* op = result.Nodes.getNodeAs<BinaryOperator>("assignment");
|
||||||
|
|
||||||
|
assert(op);
|
||||||
|
|
||||||
|
_operation_analyzer.processAssignment(op, *result.SourceManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperationFinder::_processArithmetic(const MatchFinder::MatchResult& result)
|
||||||
|
{
|
||||||
|
const BinaryOperator* op = result.Nodes.getNodeAs<clang::BinaryOperator>("arithmetic");
|
||||||
|
|
||||||
|
assert(op);
|
||||||
|
|
||||||
|
_operation_analyzer.processBinaryArithmetic(op, *result.SourceManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperationFinder::_processCompoundStmt(const clang::ast_matchers::MatchFinder::MatchResult& result)
|
||||||
|
{
|
||||||
|
const CompoundStmt* stmt = result.Nodes.getNodeAs<CompoundStmt>("compound_stmt");
|
||||||
|
|
||||||
|
assert(stmt);
|
||||||
|
|
||||||
|
const CompoundAssignOperator* op = dyn_cast<CompoundAssignOperator>(stmt->getStmtExprResult());
|
||||||
|
|
||||||
|
if (!op || !op->isCompoundAssignmentOp())
|
||||||
|
return;
|
||||||
|
|
||||||
|
_operation_analyzer.processCompoundAssignment(op, *result.SourceManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperationFinder::_processUnaryArithmetic(const MatchFinder::MatchResult &result)
|
||||||
|
{
|
||||||
|
const UnaryOperator* op = result.Nodes.getNodeAs<UnaryOperator>("unary_arithmetic");
|
||||||
|
|
||||||
|
assert(op);
|
||||||
|
|
||||||
|
_operation_analyzer.processUnaryArithmetic(op, *result.SourceManager);
|
||||||
|
}
|
||||||
28
op-finder/OperationFinder.hpp
Normal file
28
op-finder/OperationFinder.hpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 16.02.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef LLVM_PROTO_OPERATIONFINDER_HPP
|
||||||
|
#define LLVM_PROTO_OPERATIONFINDER_HPP
|
||||||
|
|
||||||
|
#include <clang/ASTMatchers/ASTMatchers.h>
|
||||||
|
#include <clang/ASTMatchers/ASTMatchFinder.h>
|
||||||
|
|
||||||
|
#include "OperationAnalyzer.hpp"
|
||||||
|
|
||||||
|
class OperationFinder : public clang::ast_matchers::MatchFinder::MatchCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void addMatcher(clang::ast_matchers::MatchFinder& finder);
|
||||||
|
|
||||||
|
virtual void run(const clang::ast_matchers::MatchFinder::MatchResult& result) override;
|
||||||
|
private:
|
||||||
|
void _processAssignment(const clang::ast_matchers::MatchFinder::MatchResult& result);
|
||||||
|
void _processArithmetic(const clang::ast_matchers::MatchFinder::MatchResult& result);
|
||||||
|
void _processCompoundStmt(const clang::ast_matchers::MatchFinder::MatchResult& result);
|
||||||
|
void _processUnaryArithmetic(const clang::ast_matchers::MatchFinder::MatchResult& result);
|
||||||
|
|
||||||
|
OperationAnalyzer _operation_analyzer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //LLVM_PROTO_OPERATIONFINDER_HPP
|
||||||
5
op-finder/OperationFinderAction.cpp
Normal file
5
op-finder/OperationFinderAction.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 24.02.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "OperationFinderAction.hpp"
|
||||||
23
op-finder/OperationFinderAction.hpp
Normal file
23
op-finder/OperationFinderAction.hpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 24.02.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef C_ANALYZER_OPERATIONFINDERACTION_HPP
|
||||||
|
#define C_ANALYZER_OPERATIONFINDERACTION_HPP
|
||||||
|
|
||||||
|
#include <clang/AST/RecursiveASTVisitor.h>
|
||||||
|
|
||||||
|
class OperationFinderAction
|
||||||
|
: public clang::RecursiveASTVisitor<OperationFinderAction>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool VisitBinaryOperation(clang::BinaryOperator* bo);
|
||||||
|
bool VisitUnaryOperation(clang::UnaryOperator* uo);
|
||||||
|
bool VisitCompoundStatement(clang::CompoundStmt* cmp);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //C_ANALYZER_OPERATIONFINDERACTION_HPP
|
||||||
25
op-finder/OperationFinderConsumer.cpp
Normal file
25
op-finder/OperationFinderConsumer.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 24.02.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "OperationFinderConsumer.hpp"
|
||||||
|
|
||||||
|
OperationFinderConsumer::OperationFinderConsumer()
|
||||||
|
{
|
||||||
|
_op_finder.addMatcher(_ast_finder);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperationFinderConsumer::HandleTranslationUnit(clang::ASTContext& context)
|
||||||
|
{
|
||||||
|
//_ast_finder.matchAST(context);
|
||||||
|
auto consumer = _ast_finder.newASTConsumer();
|
||||||
|
|
||||||
|
consumer->HandleTranslationUnit(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<clang::ASTConsumer> OperationFinderAction::CreateASTConsumer(
|
||||||
|
clang::CompilerInstance& compiler, llvm::StringRef in_file)
|
||||||
|
{
|
||||||
|
return std::unique_ptr<clang::ASTConsumer>(
|
||||||
|
new OperationFinderConsumer());
|
||||||
|
}
|
||||||
32
op-finder/OperationFinderConsumer.hpp
Normal file
32
op-finder/OperationFinderConsumer.hpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 24.02.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef C_ANALYZER_OPERATIONFINDERCONSUMER_HPP
|
||||||
|
#define C_ANALYZER_OPERATIONFINDERCONSUMER_HPP
|
||||||
|
|
||||||
|
#include <clang/AST/ASTConsumer.h>
|
||||||
|
#include <clang/Frontend/FrontendAction.h>
|
||||||
|
|
||||||
|
#include "OperationFinder.hpp"
|
||||||
|
|
||||||
|
class OperationFinderConsumer : public clang::ASTConsumer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OperationFinderConsumer();
|
||||||
|
|
||||||
|
void HandleTranslationUnit(clang::ASTContext& context) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
OperationFinder _op_finder;
|
||||||
|
clang::ast_matchers::MatchFinder _ast_finder;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OperationFinderAction : public clang::ASTFrontendAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
|
||||||
|
clang::CompilerInstance& compiler, llvm::StringRef in_file) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //C_ANALYZER_OPERATIONFINDERCONSUMER_HPP
|
||||||
62
op-finder/TestASTConsumer.hpp
Normal file
62
op-finder/TestASTConsumer.hpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 24.02.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef C_ANALYZER_TESTASTCONSUMER_HPP
|
||||||
|
#define C_ANALYZER_TESTASTCONSUMER_HPP
|
||||||
|
|
||||||
|
#include <clang/Frontend/CompilerInstance.h>
|
||||||
|
#include <clang/Frontend/FrontendActions.h>
|
||||||
|
#include <clang/AST/RecursiveASTVisitor.h>
|
||||||
|
|
||||||
|
class DebuggeringASTVisitor
|
||||||
|
: public clang::RecursiveASTVisitor<DebuggeringASTVisitor>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit DebuggeringASTVisitor(clang::ASTContext* context)
|
||||||
|
: _context(context)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
bool VisitBinaryOperator(clang::BinaryOperator* bo)
|
||||||
|
{
|
||||||
|
llvm::outs() << "OKAY FUCK YOU\n";
|
||||||
|
bo->dump();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
clang::ASTContext* _context;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DebuggeringASTConsumer : public clang::ASTConsumer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit DebuggeringASTConsumer(clang::ASTContext* context)
|
||||||
|
: _visitor(context)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleTranslationUnit(clang::ASTContext& context) override
|
||||||
|
{
|
||||||
|
_visitor.TraverseAST(context);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
DebuggeringASTVisitor _visitor;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DebuggeringASTAction : public clang::ASTFrontendAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
|
||||||
|
clang::CompilerInstance &Compiler, llvm::StringRef InFile) override
|
||||||
|
{
|
||||||
|
return std::unique_ptr<clang::ASTConsumer>(
|
||||||
|
new DebuggeringASTConsumer(&Compiler.getASTContext()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif //C_ANALYZER_TESTASTCONSUMER_HPP
|
||||||
@ -5,12 +5,9 @@
|
|||||||
// Declares llvm::cl::extrahelp.
|
// Declares llvm::cl::extrahelp.
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "OperationAstMatcher.hpp"
|
|
||||||
#include "OperationFinder.hpp"
|
#include "OperationFinder.hpp"
|
||||||
#include "OperationStorage.hpp"
|
#include "TestASTConsumer.hpp"
|
||||||
#include "OperationFinderAstAction.hpp"
|
#include "OperationFinderConsumer.hpp"
|
||||||
|
|
||||||
using namespace clang::tooling;
|
using namespace clang::tooling;
|
||||||
using namespace clang::ast_matchers;
|
using namespace clang::ast_matchers;
|
||||||
@ -18,15 +15,7 @@ using namespace llvm;
|
|||||||
|
|
||||||
// Apply a custom category to all command-line options so that they are the
|
// Apply a custom category to all command-line options so that they are the
|
||||||
// only ones displayed.
|
// only ones displayed.
|
||||||
static cl::OptionCategory MyToolCategory("op-finder options");
|
static llvm::cl::OptionCategory MyToolCategory("opcounter options");
|
||||||
|
|
||||||
static cl::opt<std::string> OutputFile("o", cl::desc("File to output the JSON to."),
|
|
||||||
cl::cat(MyToolCategory));
|
|
||||||
|
|
||||||
static cl::opt<std::string> RootDirectory("r", cl::desc("The root directory of the source files."),
|
|
||||||
cl::cat(MyToolCategory));
|
|
||||||
|
|
||||||
static cl::opt<bool> PrettyPrint("pretty", cl::desc("Pretty-print the output JSON."));
|
|
||||||
|
|
||||||
// CommonOptionsParser declares HelpMessage with a description of the common
|
// CommonOptionsParser declares HelpMessage with a description of the common
|
||||||
// command-line options related to the compilation database and input files.
|
// command-line options related to the compilation database and input files.
|
||||||
@ -34,9 +23,7 @@ static cl::opt<bool> PrettyPrint("pretty", cl::desc("Pretty-print the output JSO
|
|||||||
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
|
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
|
||||||
|
|
||||||
// A help message for this specific tool can be added afterwards.
|
// A help message for this specific tool can be added afterwards.
|
||||||
static cl::extrahelp MoreHelp("\nThe program takes the input <source0> ... files, parses their\n"
|
static cl::extrahelp MoreHelp("\nMore help text...\n");
|
||||||
"AST and outputs a singular file containing a list of all noteworthy operations\n"
|
|
||||||
"for later analysis.\n");
|
|
||||||
|
|
||||||
int main(int argc, const char** argv)
|
int main(int argc, const char** argv)
|
||||||
{
|
{
|
||||||
@ -52,30 +39,14 @@ int main(int argc, const char** argv)
|
|||||||
ClangTool Tool(OptionsParser.getCompilations(),
|
ClangTool Tool(OptionsParser.getCompilations(),
|
||||||
OptionsParser.getSourcePathList());
|
OptionsParser.getSourcePathList());
|
||||||
|
|
||||||
OperationStorage storage;
|
OperationFinder op_finder;
|
||||||
|
MatchFinder finder;
|
||||||
|
|
||||||
if (PrettyPrint.getValue())
|
op_finder.addMatcher(finder);
|
||||||
storage.enablePrettyPrint();
|
|
||||||
|
|
||||||
OperationFinder op_finder(&storage);
|
// Tool.run(newFrontendActionFactory<clang::ASTPrintAction>().get());
|
||||||
|
Tool.run(newFrontendActionFactory<DebuggeringASTAction>().get());
|
||||||
|
Tool.run(newFrontendActionFactory<OperationFinderAction>().get());
|
||||||
|
|
||||||
#if 0
|
// return Tool.run(newFrontendActionFactory(&finder).get());
|
||||||
MatchFinder matcher;
|
|
||||||
OperationASTMatcher finder(&op_finder);
|
|
||||||
|
|
||||||
finder.addToFinder(matcher);
|
|
||||||
|
|
||||||
//Tool.run(newFrontendActionFactory<DebuggeringASTAction>().get());
|
|
||||||
|
|
||||||
return Tool.run(newFrontendActionFactory(&finder).get());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
OperationFinderAstAction action(&op_finder);
|
|
||||||
|
|
||||||
Tool.run(newFrontendActionFactory(&action).get());
|
|
||||||
|
|
||||||
if (!OutputFile.getValue().empty())
|
|
||||||
storage.toFile(OutputFile.getValue());
|
|
||||||
else
|
|
||||||
storage.toStream(std::cout);
|
|
||||||
}
|
}
|
||||||
File diff suppressed because one or more lines are too long
@ -1,213 +0,0 @@
|
|||||||
{
|
|
||||||
"matrix.c": [
|
|
||||||
{
|
|
||||||
"branch_number": 1,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "=",
|
|
||||||
"type_lhs": "int",
|
|
||||||
"type_result": "int",
|
|
||||||
"type_rhs": "int"
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 20
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"branch_number": 2,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "<",
|
|
||||||
"type_lhs": "int",
|
|
||||||
"type_result": "int",
|
|
||||||
"type_rhs": "int"
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 20
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"branch_number": 2,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "++",
|
|
||||||
"type_lhs": "int",
|
|
||||||
"type_result": "int",
|
|
||||||
"type_rhs": ""
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 20
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"branch_number": 1,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "=",
|
|
||||||
"type_lhs": "int",
|
|
||||||
"type_result": "int",
|
|
||||||
"type_rhs": "int"
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 22
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"branch_number": 2,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "<",
|
|
||||||
"type_lhs": "int",
|
|
||||||
"type_result": "int",
|
|
||||||
"type_rhs": "int"
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 22
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"branch_number": 2,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "++",
|
|
||||||
"type_lhs": "int",
|
|
||||||
"type_result": "int",
|
|
||||||
"type_rhs": ""
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 22
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"branch_number": 0,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "=",
|
|
||||||
"type_lhs": "unsigned short",
|
|
||||||
"type_result": "unsigned short",
|
|
||||||
"type_rhs": "unsigned short"
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 24
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"branch_number": 0,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "subscript",
|
|
||||||
"type_lhs": "volatile UInt16 *",
|
|
||||||
"type_result": "unsigned short",
|
|
||||||
"type_rhs": "int"
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 24
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"branch_number": 0,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "subscript",
|
|
||||||
"type_lhs": "volatile UInt16 (*)[5]",
|
|
||||||
"type_result": "volatile UInt16 [5]",
|
|
||||||
"type_rhs": "int"
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 24
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"branch_number": 1,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "=",
|
|
||||||
"type_lhs": "int",
|
|
||||||
"type_result": "int",
|
|
||||||
"type_rhs": "int"
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 25
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"branch_number": 2,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "<",
|
|
||||||
"type_lhs": "int",
|
|
||||||
"type_result": "int",
|
|
||||||
"type_rhs": "int"
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 25
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"branch_number": 2,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "++",
|
|
||||||
"type_lhs": "int",
|
|
||||||
"type_result": "int",
|
|
||||||
"type_rhs": ""
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 25
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"branch_number": 0,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "subscript",
|
|
||||||
"type_lhs": "volatile UInt16 *",
|
|
||||||
"type_result": "unsigned short",
|
|
||||||
"type_rhs": "int"
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 27
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"branch_number": 0,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "subscript",
|
|
||||||
"type_lhs": "volatile UInt16 (*)[5]",
|
|
||||||
"type_result": "volatile UInt16 [5]",
|
|
||||||
"type_rhs": "int"
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 27
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"branch_number": 0,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "*",
|
|
||||||
"type_lhs": "int",
|
|
||||||
"type_result": "int",
|
|
||||||
"type_rhs": "int"
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 27
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"branch_number": 0,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "subscript",
|
|
||||||
"type_lhs": "const UInt16 *",
|
|
||||||
"type_result": "unsigned short",
|
|
||||||
"type_rhs": "int"
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 27
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"branch_number": 0,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "subscript",
|
|
||||||
"type_lhs": "const UInt16 (*)[4]",
|
|
||||||
"type_result": "const UInt16 [4]",
|
|
||||||
"type_rhs": "int"
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 27
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"branch_number": 0,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "subscript",
|
|
||||||
"type_lhs": "const UInt16 *",
|
|
||||||
"type_result": "unsigned short",
|
|
||||||
"type_rhs": "int"
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 27
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"branch_number": 0,
|
|
||||||
"entry": {
|
|
||||||
"operation_name": "subscript",
|
|
||||||
"type_lhs": "const UInt16 (*)[5]",
|
|
||||||
"type_result": "const UInt16 [5]",
|
|
||||||
"type_rhs": "int"
|
|
||||||
},
|
|
||||||
"entry_type": "basic_operation",
|
|
||||||
"line": 27
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
import json
|
|
||||||
|
|
||||||
from dataclasses import dataclass
|
|
||||||
from typing import Dict, List
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class GCovLine:
|
|
||||||
line_number: int
|
|
||||||
count: int
|
|
||||||
branch_number: int = 0
|
|
||||||
|
|
||||||
|
|
||||||
class GCovFile:
|
|
||||||
def __init__(self, path: str) -> None:
|
|
||||||
self._path = path
|
|
||||||
self._data: dict = {}
|
|
||||||
|
|
||||||
self.files: Dict[str, List[GCovLine]] = {}
|
|
||||||
|
|
||||||
def read(self) -> None:
|
|
||||||
with open(self._path, "r") as infile:
|
|
||||||
self._data = json.load(infile)
|
|
||||||
|
|
||||||
for file in self._data["files"]:
|
|
||||||
name: str = file["file"]
|
|
||||||
lines: List[GCovLine] = []
|
|
||||||
|
|
||||||
for line in file["lines"]:
|
|
||||||
# Branch specific identification. TODO! later.
|
|
||||||
lines.append(GCovLine(line["line_number"], line["count"]))
|
|
||||||
if len(line["branches"]):
|
|
||||||
# GCov reports branches in reverse order to our parser.
|
|
||||||
branch_number = len(line["branches"])
|
|
||||||
for branch in line["branches"]:
|
|
||||||
lines.append(GCovLine(line["line_number"], branch["count"], branch_number))
|
|
||||||
branch_number -= 1
|
|
||||||
|
|
||||||
self.files[name] = lines
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
import json
|
|
||||||
|
|
||||||
from enum import Enum
|
|
||||||
from dataclasses import dataclass
|
|
||||||
from typing import Any, Dict, List, Union
|
|
||||||
|
|
||||||
|
|
||||||
class OperationType(Enum):
|
|
||||||
BASIC = "basic_operation"
|
|
||||||
FUNCTION_CALL = "function_call"
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class BasicOperation:
|
|
||||||
operation_name: str
|
|
||||||
type_lhs: str
|
|
||||||
type_rhs: str
|
|
||||||
type_result: str
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class FunctionCall:
|
|
||||||
function_name: str
|
|
||||||
call_result_type: str
|
|
||||||
|
|
||||||
|
|
||||||
UniqueOperation = Union[BasicOperation, FunctionCall]
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class OperationLog:
|
|
||||||
line: int
|
|
||||||
branch_number: int
|
|
||||||
entry_type: OperationType
|
|
||||||
entry: UniqueOperation
|
|
||||||
|
|
||||||
def __post_init__(self) -> None:
|
|
||||||
self.entry_type = OperationType(self.entry_type)
|
|
||||||
|
|
||||||
if self.entry_type == OperationType.BASIC:
|
|
||||||
self.entry = BasicOperation(**self.entry)
|
|
||||||
elif self.entry_type == OperationType.FUNCTION_CALL:
|
|
||||||
self.entry = FunctionCall(**self.entry)
|
|
||||||
else:
|
|
||||||
assert False, "Unaccounted for operation type."
|
|
||||||
|
|
||||||
|
|
||||||
class OperationLogReader:
|
|
||||||
def __init__(self, path: str) -> None:
|
|
||||||
self._path = path
|
|
||||||
self._data: dict = {}
|
|
||||||
|
|
||||||
self.files: Dict[str, List[OperationLog]] = {}
|
|
||||||
|
|
||||||
def read(self) -> None:
|
|
||||||
with open(self._path, "r") as infile:
|
|
||||||
self._data = json.load(infile)
|
|
||||||
|
|
||||||
for name, ops_list in self._data.items():
|
|
||||||
ops: List[OperationLog] = []
|
|
||||||
|
|
||||||
for op_json in ops_list:
|
|
||||||
ops.append(OperationLog(**op_json))
|
|
||||||
|
|
||||||
self.files[name] = ops
|
|
||||||
|
|
||||||
def get_lines(self, file: str, line_number: int) -> List[OperationLog]:
|
|
||||||
res: List[OperationLog] = []
|
|
||||||
for line in self.files[file]:
|
|
||||||
if line.line == line_number:
|
|
||||||
res.append(line)
|
|
||||||
|
|
||||||
return res
|
|
||||||
@ -1,140 +0,0 @@
|
|||||||
import json
|
|
||||||
|
|
||||||
from dataclasses import asdict
|
|
||||||
from typing import Dict, List, Tuple
|
|
||||||
|
|
||||||
from gcovreader import GCovFile
|
|
||||||
from opfinderreader import OperationLogReader, UniqueOperation, OperationLog
|
|
||||||
|
|
||||||
|
|
||||||
class OpSummarizer:
|
|
||||||
def __init__(self, gcov_path: str, opfinder_path: str) -> None:
|
|
||||||
self.gcov = GCovFile(gcov_path)
|
|
||||||
self.ops = OperationLogReader(opfinder_path)
|
|
||||||
|
|
||||||
self.gcov.read()
|
|
||||||
self.ops.read()
|
|
||||||
|
|
||||||
self.model: Dict[UniqueOperation, Tuple[float, float]] = None
|
|
||||||
self.uncounted_estimates: Dict[UniqueOperation, int] = {}
|
|
||||||
self.energy_consumption_estimation = 0.0
|
|
||||||
self.execution_time_estimation = 0.0
|
|
||||||
|
|
||||||
def add_model(self, model_path: str) -> None:
|
|
||||||
with open(model_path, "r") as model_file:
|
|
||||||
data = json.load(model_file)
|
|
||||||
|
|
||||||
assert type(data) == list, "Model file did not contain a JSON list."
|
|
||||||
|
|
||||||
self.model = {}
|
|
||||||
for entry in data:
|
|
||||||
unique_op = OperationLog(**entry["unique_operation"]).entry
|
|
||||||
energy = entry["energy_consumption"]
|
|
||||||
time = entry["execution_time"]
|
|
||||||
|
|
||||||
self.model[unique_op] = [energy, time]
|
|
||||||
|
|
||||||
def count_operations(self, file: str) -> Dict[UniqueOperation, int]:
|
|
||||||
if file not in self.gcov.files or file not in self.ops.files:
|
|
||||||
print(f"Gcov files: {self.gcov.files.keys()}")
|
|
||||||
print(f"Opfinder files: {self.ops.files.keys()}")
|
|
||||||
raise RuntimeError(f"File {file} not in both parsers.")
|
|
||||||
|
|
||||||
op_counter: Dict[UniqueOperation, int] = {}
|
|
||||||
|
|
||||||
for gcov_line in self.gcov.files[file]:
|
|
||||||
op_lines = self.ops.get_lines(file, gcov_line.line_number)
|
|
||||||
for op_log in op_lines:
|
|
||||||
# TODO: revise this. Need a special case for for-loop clauses
|
|
||||||
# or branching in general.
|
|
||||||
if op_log.branch_number != gcov_line.branch_number:
|
|
||||||
continue
|
|
||||||
|
|
||||||
unique_op = op_log.entry
|
|
||||||
|
|
||||||
if unique_op in op_counter:
|
|
||||||
op_counter[unique_op] += gcov_line.count
|
|
||||||
else:
|
|
||||||
op_counter[unique_op] = gcov_line.count
|
|
||||||
|
|
||||||
return op_counter
|
|
||||||
|
|
||||||
def update_estimations(self, uops: Dict[UniqueOperation, int]) -> None:
|
|
||||||
assert self.model, "Model not populated."
|
|
||||||
for unique_op, op_count in uops.items():
|
|
||||||
if unique_op in self.model:
|
|
||||||
energy, time = self.model[unique_op]
|
|
||||||
self.energy_consumption_estimation += energy * op_count
|
|
||||||
self.execution_time_estimation += time * op_count
|
|
||||||
elif unique_op in self.uncounted_estimates:
|
|
||||||
self.uncounted_estimates[unique_op] += op_count
|
|
||||||
else:
|
|
||||||
self.uncounted_estimates[unique_op] = op_count
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def operation_count_to_json_dict(unique_ops: Dict[UniqueOperation, int]) -> List[Dict]:
|
|
||||||
out = []
|
|
||||||
|
|
||||||
for uo, uo_count in unique_ops.items():
|
|
||||||
d = asdict(uo)
|
|
||||||
d["count"] = uo_count
|
|
||||||
out.append(d)
|
|
||||||
|
|
||||||
return out
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description="Merges gcovr and op-finder outputs.")
|
|
||||||
parser.add_argument("files", metavar="FILES", type=str, nargs="+",
|
|
||||||
help="The files to accumulate.")
|
|
||||||
parser.add_argument("--gcov", type=str, default="./data/gcov.json",
|
|
||||||
help="The gcovr json file to use.")
|
|
||||||
parser.add_argument("--finder", type=str, default="./data/opfinder.json",
|
|
||||||
help="The op-finder json file to use.")
|
|
||||||
parser.add_argument("--output", type=str, default=None, required=False,
|
|
||||||
help="The file to output the data to.")
|
|
||||||
parser.add_argument("--model", type=str, default=None, required=False,
|
|
||||||
help="The JSON file containing the system model.")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
summarizer = OpSummarizer(args.gcov, args.finder)
|
|
||||||
|
|
||||||
if args.model:
|
|
||||||
summarizer.add_model(args.model)
|
|
||||||
|
|
||||||
uops_dictionary = {}
|
|
||||||
total_num = 0
|
|
||||||
|
|
||||||
for file_name in args.files:
|
|
||||||
ops = summarizer.count_operations(file_name)
|
|
||||||
uops_dictionary[file_name] = summarizer.operation_count_to_json_dict(ops)
|
|
||||||
|
|
||||||
if args.model:
|
|
||||||
summarizer.update_estimations(ops)
|
|
||||||
|
|
||||||
print(f"Unique operations for file {file_name}:")
|
|
||||||
for uop, count in ops.items():
|
|
||||||
print(f"\t{count}: {uop}")
|
|
||||||
total_num += count
|
|
||||||
|
|
||||||
print("---------")
|
|
||||||
|
|
||||||
print(f"Total count: {total_num}")
|
|
||||||
|
|
||||||
if args.output:
|
|
||||||
with open(args.output, "w") as outfile:
|
|
||||||
json.dump(uops_dictionary, outfile)
|
|
||||||
|
|
||||||
if args.model:
|
|
||||||
power_usage_estimate = summarizer.energy_consumption_estimation
|
|
||||||
time_estimate = summarizer.execution_time_estimation
|
|
||||||
print("---------")
|
|
||||||
print(f"Total energy usage estimation: {power_usage_estimate} mJ\nTotal execution time estimation: {time_estimate} ms")
|
|
||||||
if summarizer.uncounted_estimates:
|
|
||||||
print("Operations not accounted for (missing from the model):")
|
|
||||||
for uop, count in summarizer.uncounted_estimates.items():
|
|
||||||
print(f"\t{uop}: {count}")
|
|
||||||
else:
|
|
||||||
print("No operations missing from the model.")
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
import unittest
|
|
||||||
import subprocess
|
|
||||||
import json
|
|
||||||
|
|
||||||
from dataclasses import asdict
|
|
||||||
from typing import Dict
|
|
||||||
|
|
||||||
from opfinderreader import UniqueOperation
|
|
||||||
from opsummarizer import OpSummarizer
|
|
||||||
|
|
||||||
|
|
||||||
class Compiler:
|
|
||||||
def __init__(self, root_file: str) -> None:
|
|
||||||
self.root_file = root_file
|
|
||||||
self.gcov_file = f"./{root_file}_gcov.json"
|
|
||||||
self.opfinder_file = f"./{root_file}_opfinder.json"
|
|
||||||
|
|
||||||
def compile_and_profile(self) -> None:
|
|
||||||
output_file = f"{self.root_file}.out"
|
|
||||||
input_file = f"{self.root_file}.c"
|
|
||||||
|
|
||||||
subprocess.call(["gcc",
|
|
||||||
"-fprofile-arcs",
|
|
||||||
"-ftest-coverage",
|
|
||||||
"-o", output_file,
|
|
||||||
input_file])
|
|
||||||
|
|
||||||
subprocess.call([f"./{output_file}"])
|
|
||||||
|
|
||||||
subprocess.call(["gcovr",
|
|
||||||
"-r", ".",
|
|
||||||
"--json",
|
|
||||||
"--output", self.gcov_file])
|
|
||||||
|
|
||||||
def find_operations(self) -> None:
|
|
||||||
input_file = f"{self.root_file}.c"
|
|
||||||
|
|
||||||
subprocess.call(["./op-finder",
|
|
||||||
"-o", self.opfinder_file,
|
|
||||||
input_file])
|
|
||||||
|
|
||||||
|
|
||||||
class SummarizerCreatesExpectedOutput(unittest.TestCase):
|
|
||||||
def __init__(self, test_name, file_name) -> None:
|
|
||||||
super(SummarizerCreatesExpectedOutput, self).__init__(test_name)
|
|
||||||
self.root_file_name = file_name
|
|
||||||
self.compiler = Compiler(file_name)
|
|
||||||
|
|
||||||
def setUp(self) -> None:
|
|
||||||
self.compiler.compile_and_profile()
|
|
||||||
self.compiler.find_operations()
|
|
||||||
|
|
||||||
def _get_etalon(self) -> Dict:
|
|
||||||
filename = f"{self.root_file_name}_expected.json"
|
|
||||||
with open(filename, "r") as f:
|
|
||||||
return json.load(f)[f"{self.root_file_name}.c"]
|
|
||||||
|
|
||||||
def test_summarizer_output(self) -> None:
|
|
||||||
summarizer = OpSummarizer(self.compiler.gcov_file, self.compiler.opfinder_file)
|
|
||||||
found = summarizer.count_operations(f"{self.root_file_name}.c")
|
|
||||||
found = summarizer.operation_count_to_json_dict(found)
|
|
||||||
|
|
||||||
etalon = self._get_etalon()
|
|
||||||
|
|
||||||
self.assertEqual(found, etalon, msg="Found operations doesn't match etalon dictionary.")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
suite = unittest.TestSuite()
|
|
||||||
|
|
||||||
suite.addTest(SummarizerCreatesExpectedOutput("test_summarizer_output", "matrix"))
|
|
||||||
# suite.addTest(SummarizerCreatesExpectedOutput("test_summarizer_output", "gauss_blur"))
|
|
||||||
# suite.addTest(SummarizerCreatesExpectedOutput("test_summarizer_output", "for_loop"))
|
|
||||||
# suite.addTest(SummarizerCreatesExpectedOutput("test_summarizer_output", "fir"))
|
|
||||||
|
|
||||||
unittest.TextTestRunner(verbosity=2).run(suite)
|
|
||||||
@ -1,235 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
*
|
|
||||||
* Name : Dhrystone
|
|
||||||
* Purpose : Benchmark the Dhrystone code. This benchmark is used to gauge
|
|
||||||
* the performance of the microcontroller in handling pointers,
|
|
||||||
* structures and strings.
|
|
||||||
*
|
|
||||||
*******************************************************************************/
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define LOOPS 100 /* Use this for slow or 16 bit machines */
|
|
||||||
#define structassign(d, s) d = s
|
|
||||||
typedef enum {
|
|
||||||
Ident1, Ident2, Ident3, Ident4, Ident5
|
|
||||||
} Enumeration;
|
|
||||||
typedef int OneToThirty;
|
|
||||||
typedef int OneToFifty;
|
|
||||||
typedef unsigned char CapitalLetter;
|
|
||||||
typedef unsigned char String30[31];
|
|
||||||
typedef int Array1Dim[51];
|
|
||||||
typedef int Array2Dim[10][10];
|
|
||||||
struct Record
|
|
||||||
{
|
|
||||||
struct Record *PtrComp;
|
|
||||||
Enumeration Discr;
|
|
||||||
Enumeration EnumComp;
|
|
||||||
OneToFifty IntComp;
|
|
||||||
String30 StringComp;
|
|
||||||
};
|
|
||||||
typedef struct Record RecordType;
|
|
||||||
typedef RecordType * RecordPtr;
|
|
||||||
typedef int boolean;
|
|
||||||
//#define NULL 0
|
|
||||||
#define TRUE 1
|
|
||||||
#define FALSE 0
|
|
||||||
#define REG register
|
|
||||||
int IntGlob;
|
|
||||||
boolean BoolGlob;
|
|
||||||
unsigned char Char1Glob;
|
|
||||||
unsigned char Char2Glob;
|
|
||||||
Array1Dim Array1Glob;
|
|
||||||
Array2Dim Array2Glob;
|
|
||||||
RecordPtr PtrGlb;
|
|
||||||
RecordPtr PtrGlbNext;
|
|
||||||
RecordType rec1, rec2;
|
|
||||||
Enumeration Func1(CapitalLetter CharPar1, CapitalLetter CharPar2) {
|
|
||||||
REG CapitalLetter CharLoc1;
|
|
||||||
REG CapitalLetter CharLoc2;
|
|
||||||
CharLoc1 = CharPar1;
|
|
||||||
CharLoc2 = CharLoc1;
|
|
||||||
if (CharLoc2 != CharPar2)
|
|
||||||
return (Ident1);
|
|
||||||
else
|
|
||||||
return (Ident2);
|
|
||||||
}
|
|
||||||
boolean Func2(String30 StrParI1, String30 StrParI2) {
|
|
||||||
REG OneToThirty IntLoc;
|
|
||||||
REG CapitalLetter CharLoc;
|
|
||||||
IntLoc = 1;
|
|
||||||
while (IntLoc <= 1)
|
|
||||||
if (Func1(StrParI1[IntLoc], StrParI2[IntLoc + 1]) == Ident1) {
|
|
||||||
CharLoc = 'A';
|
|
||||||
++IntLoc;
|
|
||||||
}
|
|
||||||
if (CharLoc >= 'W' && CharLoc <= 'Z')
|
|
||||||
IntLoc = 7;
|
|
||||||
if (CharLoc == 'X')
|
|
||||||
return (TRUE);
|
|
||||||
else {
|
|
||||||
if (strcmp(StrParI1, StrParI2) > 0) {
|
|
||||||
IntLoc += 7;
|
|
||||||
return (TRUE);
|
|
||||||
} else
|
|
||||||
return (FALSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
boolean Func3(Enumeration EnumParIn) {
|
|
||||||
REG Enumeration EnumLoc;
|
|
||||||
EnumLoc = EnumParIn;
|
|
||||||
if (EnumLoc == Ident3)
|
|
||||||
return (TRUE);
|
|
||||||
return (FALSE);
|
|
||||||
}
|
|
||||||
void Proc7(OneToFifty IntParI1, OneToFifty IntParI2, OneToFifty *IntParOut) {
|
|
||||||
REG OneToFifty IntLoc;
|
|
||||||
IntLoc = IntParI1 + 2;
|
|
||||||
*IntParOut = IntParI2 + IntLoc;
|
|
||||||
}
|
|
||||||
void Proc4(void) {
|
|
||||||
REG boolean BoolLoc;
|
|
||||||
BoolLoc = Char1Glob == 'A';
|
|
||||||
BoolLoc |= BoolGlob;
|
|
||||||
Char2Glob = 'B';
|
|
||||||
}
|
|
||||||
void Proc5(void) {
|
|
||||||
Char1Glob = 'A';
|
|
||||||
BoolGlob = FALSE;
|
|
||||||
}
|
|
||||||
void Proc6(Enumeration EnumParIn, Enumeration *EnumParOut) {
|
|
||||||
*EnumParOut = EnumParIn;
|
|
||||||
if (!Func3(EnumParIn))
|
|
||||||
*EnumParOut = Ident4;
|
|
||||||
switch (EnumParIn) {
|
|
||||||
case Ident1:
|
|
||||||
*EnumParOut = Ident1;
|
|
||||||
break;
|
|
||||||
case Ident2:
|
|
||||||
if (IntGlob > 100)
|
|
||||||
*EnumParOut = Ident1;
|
|
||||||
else
|
|
||||||
*EnumParOut = Ident4;
|
|
||||||
break;
|
|
||||||
case Ident3:
|
|
||||||
*EnumParOut = Ident2;
|
|
||||||
break;
|
|
||||||
case Ident4:
|
|
||||||
break;
|
|
||||||
case Ident5:
|
|
||||||
*EnumParOut = Ident3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void Proc3(RecordPtr *PtrParOut) {
|
|
||||||
if (PtrGlb != NULL)
|
|
||||||
*PtrParOut = PtrGlb->PtrComp;
|
|
||||||
else
|
|
||||||
IntGlob = 100;
|
|
||||||
Proc7(10, IntGlob, &PtrGlb->IntComp);
|
|
||||||
}
|
|
||||||
void Proc1(RecordPtr PtrParIn) {
|
|
||||||
#define NextRecord (*(PtrParIn->PtrComp))
|
|
||||||
structassign(NextRecord, *PtrGlb);
|
|
||||||
PtrParIn->IntComp = 5;
|
|
||||||
NextRecord.IntComp = PtrParIn->IntComp;
|
|
||||||
NextRecord.PtrComp = PtrParIn->PtrComp;
|
|
||||||
Proc3(&NextRecord.PtrComp);
|
|
||||||
if (NextRecord.Discr == Ident1) {
|
|
||||||
NextRecord.IntComp = 6;
|
|
||||||
Proc6(PtrParIn->EnumComp, &NextRecord.EnumComp);
|
|
||||||
NextRecord.PtrComp = PtrGlb->PtrComp;
|
|
||||||
Proc7(NextRecord.IntComp, 10, &NextRecord.IntComp);
|
|
||||||
} else
|
|
||||||
structassign(*PtrParIn, NextRecord);
|
|
||||||
#undef NextRecord
|
|
||||||
}
|
|
||||||
void Proc2(OneToFifty *IntParIO) {
|
|
||||||
REG OneToFifty IntLoc;
|
|
||||||
REG Enumeration EnumLoc;
|
|
||||||
IntLoc = *IntParIO + 10;
|
|
||||||
for (;;) {
|
|
||||||
if (Char1Glob == 'A') {
|
|
||||||
--IntLoc;
|
|
||||||
*IntParIO = IntLoc - IntGlob;
|
|
||||||
EnumLoc = Ident1;
|
|
||||||
}
|
|
||||||
if (EnumLoc == Ident1)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void Proc8(Array1Dim Array1Par, Array2Dim Array2Par, OneToFifty IntParI1,
|
|
||||||
OneToFifty IntParI2) {
|
|
||||||
REG OneToFifty IntLoc;
|
|
||||||
REG OneToFifty IntIndex;
|
|
||||||
IntLoc = IntParI1 + 5;
|
|
||||||
Array1Par[IntLoc] = IntParI2;
|
|
||||||
Array1Par[IntLoc + 1] = Array1Par[IntLoc];
|
|
||||||
Array1Par[IntLoc + 30] = IntLoc;
|
|
||||||
for (IntIndex = IntLoc; IntIndex <= (IntLoc + 1); ++IntIndex)
|
|
||||||
Array2Par[IntLoc][IntIndex] = IntLoc;
|
|
||||||
++Array2Par[IntLoc][IntLoc - 1];
|
|
||||||
Array2Par[IntLoc + 20][IntLoc] = Array1Par[IntLoc];
|
|
||||||
IntGlob = 5;
|
|
||||||
}
|
|
||||||
void Proc0(void) {
|
|
||||||
OneToFifty IntLoc1;
|
|
||||||
REG OneToFifty IntLoc2;
|
|
||||||
OneToFifty IntLoc3;
|
|
||||||
REG unsigned char CharLoc;
|
|
||||||
REG unsigned char CharIndex;
|
|
||||||
Enumeration EnumLoc;
|
|
||||||
String30 String1Loc;
|
|
||||||
String30 String2Loc;
|
|
||||||
//extern unsigned char *malloc();
|
|
||||||
long time(long *);
|
|
||||||
long starttime;
|
|
||||||
long benchtime;
|
|
||||||
long nulltime;
|
|
||||||
register unsigned int i;
|
|
||||||
for (i = 0; i < LOOPS; ++i)
|
|
||||||
;
|
|
||||||
PtrGlbNext = &rec1; /* (RecordPtr) malloc(sizeof(RecordType)); */
|
|
||||||
PtrGlb = &rec2; /* (RecordPtr) malloc(sizeof(RecordType)); */
|
|
||||||
PtrGlb->PtrComp = PtrGlbNext;
|
|
||||||
PtrGlb->Discr = Ident1;
|
|
||||||
PtrGlb->EnumComp = Ident3;
|
|
||||||
PtrGlb->IntComp = 40;
|
|
||||||
strcpy(PtrGlb->StringComp, "DHRYSTONE PROGRAM, SOME STRING");
|
|
||||||
strcpy(String1Loc, "DHRYSTONE PROGRAM, 1'ST STRING"); /*GOOF*/
|
|
||||||
Array2Glob[8][7] = 10; /* Was missing in published program */
|
|
||||||
for (i = 0; i < LOOPS; ++i) {
|
|
||||||
Proc5();
|
|
||||||
Proc4();
|
|
||||||
IntLoc1 = 2;
|
|
||||||
IntLoc2 = 3;
|
|
||||||
strcpy(String2Loc, "DHRYSTONE PROGRAM, 2'ND STRING");
|
|
||||||
EnumLoc = Ident2;
|
|
||||||
BoolGlob = !Func2(String1Loc, String2Loc);
|
|
||||||
while (IntLoc1 < IntLoc2) {
|
|
||||||
IntLoc3 = 5 * IntLoc1 - IntLoc2;
|
|
||||||
Proc7(IntLoc1, IntLoc2, &IntLoc3);
|
|
||||||
++IntLoc1;
|
|
||||||
}
|
|
||||||
Proc8(Array1Glob, Array2Glob, IntLoc1, IntLoc3);
|
|
||||||
Proc1(PtrGlb);
|
|
||||||
for (CharIndex = 'A'; CharIndex <= Char2Glob; ++CharIndex)
|
|
||||||
if (EnumLoc == Func1(CharIndex, 'C'))
|
|
||||||
Proc6(Ident1, &EnumLoc);
|
|
||||||
IntLoc3 = IntLoc2 * IntLoc1;
|
|
||||||
IntLoc2 = IntLoc3 / IntLoc1;
|
|
||||||
IntLoc2 = 7 * (IntLoc3 - IntLoc2) - IntLoc1;
|
|
||||||
Proc2(&IntLoc1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int main(void) {
|
|
||||||
// TRISG = 0;
|
|
||||||
//PORTG = 0;
|
|
||||||
int i;
|
|
||||||
//while(1){
|
|
||||||
// LATGINV = 0x0001;
|
|
||||||
for(i = 0; i < 100; i++){
|
|
||||||
Proc0();
|
|
||||||
}
|
|
||||||
//}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,241 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
*
|
|
||||||
* Name : Whetstone
|
|
||||||
* Purpose : Benchmark the Whetstone code. The code focuses on scientific
|
|
||||||
* functions such as sine, cosine, exponents and logarithm on
|
|
||||||
* fixed and floating point numbers.
|
|
||||||
*
|
|
||||||
***************************************************************************/
|
|
||||||
/* List of changes (since TI slaa205b.pdf):
|
|
||||||
- void type of PA(), P0(), P3()
|
|
||||||
- dummy functions to prevent optimization
|
|
||||||
- float (not double) variants of math funcions and constants (this
|
|
||||||
is no matter for AVR)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __AVR__
|
|
||||||
# define atanf(x) atan(x)
|
|
||||||
# define cosf(x) cos(x)
|
|
||||||
# define expf(x) exp(x)
|
|
||||||
# define logf(x) log(x)
|
|
||||||
# define sinf(x) sin(x)
|
|
||||||
# define sqrtf(x) sqrt(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Extern functions. To prevent compiler's optimization. */
|
|
||||||
void dummy1 (float x ){}
|
|
||||||
void dummy2 (float x , float y){}
|
|
||||||
|
|
||||||
void PA (float E[5]);
|
|
||||||
void P0 (void);
|
|
||||||
void P3 (float *X, float *Y, float *Z);
|
|
||||||
|
|
||||||
float T, T1, T2, E1[5];
|
|
||||||
int J, K, L;
|
|
||||||
float X1, X2, X3, X4;
|
|
||||||
long ptime, time0;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
//TRISG = 0;
|
|
||||||
//PORTG = 0;
|
|
||||||
int i;
|
|
||||||
//while(1){
|
|
||||||
//LATGINV = 0x0001;
|
|
||||||
for(i = 0; i < 100; i++){
|
|
||||||
|
|
||||||
int LOOP, I, II, JJ, N1, N2, N3, N4, N5, N6, N7, N8, N9, N10, N11;
|
|
||||||
float X, Y, Z;
|
|
||||||
T = .499975;
|
|
||||||
T1 = 0.50025;
|
|
||||||
T2 = 2.0;
|
|
||||||
LOOP = 1;
|
|
||||||
II = 1;
|
|
||||||
|
|
||||||
for (JJ = 1; JJ <= II; JJ++) {
|
|
||||||
N1 = 0;
|
|
||||||
N2 = 2 * LOOP;
|
|
||||||
N3 = 2 * LOOP;
|
|
||||||
N4 = 2 * LOOP;
|
|
||||||
N5 = 0;
|
|
||||||
N6 = 2 * LOOP;
|
|
||||||
N7 = 2 * LOOP;
|
|
||||||
N8 = 2 * LOOP;
|
|
||||||
N9 = 2 * LOOP;
|
|
||||||
N10 = 0;
|
|
||||||
N11 = 2 * LOOP;
|
|
||||||
|
|
||||||
/* Module 1: Simple identifiers */
|
|
||||||
X1 = 1.0;
|
|
||||||
X2 = -1.0;
|
|
||||||
X3 = -1.0;
|
|
||||||
X4 = -1.0;
|
|
||||||
if (N1 != 0) {
|
|
||||||
for (I = 1; I <= N1; I++) {
|
|
||||||
X1 = (X1 + X2 + X3 - X4) * T;
|
|
||||||
X2 = (X1 + X2 - X3 + X4) * T;
|
|
||||||
X3 = (X1 - X2 + X3 + X4) * T;
|
|
||||||
X4 = (-X1 + X2 + X3 + X4) * T;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Module 2: Array elements */
|
|
||||||
E1[1] = 1.0;
|
|
||||||
E1[2] = -1.0;
|
|
||||||
E1[3] = -1.0;
|
|
||||||
E1[4] = -1.0;
|
|
||||||
if (N2 != 0) {
|
|
||||||
for (I = 1; I <= N2; I++) {
|
|
||||||
E1[1] = (E1[1] + E1[2] + E1[3] - E1[4]) * T;
|
|
||||||
E1[2] = (E1[1] + E1[2] - E1[3] + E1[4]) * T;
|
|
||||||
E1[3] = (E1[1] - E1[2] + E1[3] + E1[4]) * T;
|
|
||||||
E1[4] = (-E1[1] + E1[2] + E1[3] + E1[4]) * T;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Module 3: Array as parameter */
|
|
||||||
if (N3 != 0) {
|
|
||||||
for (I = 1; I <= N3; I++) {
|
|
||||||
PA (E1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Module 4: Conditional jumps */
|
|
||||||
J = 1;
|
|
||||||
if (N4 != 0) {
|
|
||||||
for (I = 1; I <= N4; I++) {
|
|
||||||
if (J == 1)
|
|
||||||
goto L51;
|
|
||||||
J = 3;
|
|
||||||
goto L52;
|
|
||||||
L51:
|
|
||||||
J = 2;
|
|
||||||
L52:
|
|
||||||
if (J > 2)
|
|
||||||
goto L53;
|
|
||||||
J = 1;
|
|
||||||
goto L54;
|
|
||||||
L53:
|
|
||||||
J = 0;
|
|
||||||
L54:
|
|
||||||
if (J < 1)
|
|
||||||
goto L55;
|
|
||||||
J = 0;
|
|
||||||
goto L60;
|
|
||||||
L55:
|
|
||||||
J = 1;
|
|
||||||
L60: ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Module 5: Integer arithmetic */
|
|
||||||
J = 1;
|
|
||||||
K = 2;
|
|
||||||
L = 3;
|
|
||||||
if (N6 != 0) { /* ??? Where is N5? */
|
|
||||||
for (I = 1; I <= N6; I++) {
|
|
||||||
J = J * (K - J) * (L - K);
|
|
||||||
K = L * K - (L - J) * K;
|
|
||||||
L = (L - K) * (K + J);
|
|
||||||
E1[L - 1] = J + K + L;
|
|
||||||
E1[K - 1] = J * K * L;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Module 6: Trigonometric functions */
|
|
||||||
X = 0.5;
|
|
||||||
Y = 0.5;
|
|
||||||
if (N7 != 0) {
|
|
||||||
for (I = 1; I <= N7; I++) {
|
|
||||||
X = T * atanf (T2 * sinf (X) * cosf (X) /
|
|
||||||
(cosf (X + Y) + cosf (X - Y) - 1.0f));
|
|
||||||
Y = T * atanf (T2 * sinf (Y) * cosf (Y) /
|
|
||||||
(cosf (X + Y) + cosf (X - Y) - 1.0f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dummy2 (X, Y);
|
|
||||||
|
|
||||||
/* Module 7: Procedure calls */
|
|
||||||
X = 1.0;
|
|
||||||
Y = 1.0;
|
|
||||||
Z = 1.0;
|
|
||||||
if (N8 != 0) {
|
|
||||||
for (I = 1; I <= N8; I++) {
|
|
||||||
P3 (&X, &Y, &Z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Module 8: Array references */
|
|
||||||
J = 1;
|
|
||||||
K = 2;
|
|
||||||
L = 3;
|
|
||||||
E1[1] = 1.0;
|
|
||||||
E1[2] = 2.0;
|
|
||||||
E1[3] = 3.0;
|
|
||||||
if (N9 != 0) {
|
|
||||||
for (I = 1; I <= N9; I++) {
|
|
||||||
P0 ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Module 9: Integer arithmetic */
|
|
||||||
J = 2;
|
|
||||||
K = 3;
|
|
||||||
if (N10 != 0) { /* TI skips this strange test. */
|
|
||||||
for (I = 1; I <= N10; I++) {
|
|
||||||
J = J + K;
|
|
||||||
K = J + K;
|
|
||||||
J = K - J;
|
|
||||||
K = K - J - J;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Module 10: Standard functions */
|
|
||||||
X = 0.75;
|
|
||||||
if (N11 != 0) {
|
|
||||||
for (I = 1; I <= N11; I++) {
|
|
||||||
X = sqrtf (expf (logf (X) / T1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dummy1 (X);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
void PA (float E[5])
|
|
||||||
{
|
|
||||||
int J1;
|
|
||||||
J1 = 0;
|
|
||||||
L10:
|
|
||||||
E[1] = (E[1] + E[2] + E[3] - E[4]) * T;
|
|
||||||
E[2] = (E[1] + E[2] - E[3] + E[4]) * T;
|
|
||||||
E[3] = (E[1] - E[2] + E[3] + E[4]) * T;
|
|
||||||
E[4] = (-E[1] + E[2] + E[3] + E[4]) / T2;
|
|
||||||
J1 = J1 + 1;
|
|
||||||
if ((J1 - 6) < 0)
|
|
||||||
goto L10;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void P0 ()
|
|
||||||
{
|
|
||||||
E1[J] = E1[K];
|
|
||||||
E1[K] = E1[L];
|
|
||||||
E1[L] = E1[J];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void P3 (float *X, float *Y, float *Z)
|
|
||||||
{
|
|
||||||
float Y1;
|
|
||||||
X1 = *X;
|
|
||||||
Y1 = *Y;
|
|
||||||
X1 = T * (X1 + Y1);
|
|
||||||
Y1 = T * (X1 + Y1);
|
|
||||||
*Z = (X1 + Y1) / T2;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
24
testcases/assignment.c
Normal file
24
testcases/assignment.c
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#define A (unsigned long)4
|
||||||
|
#define STUFF int c = a + b
|
||||||
|
|
||||||
|
#warning butts
|
||||||
|
|
||||||
|
#include "stuff.h"
|
||||||
|
|
||||||
|
void g()
|
||||||
|
{
|
||||||
|
int a = 4;
|
||||||
|
int b = 6;
|
||||||
|
|
||||||
|
int c = a + b;
|
||||||
|
(void)c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
short a = A;
|
||||||
|
char b = 3;
|
||||||
|
|
||||||
|
STUFF;
|
||||||
|
int c2 = a + A;
|
||||||
|
}
|
||||||
@ -1 +0,0 @@
|
|||||||
{"fir.c": [{"operation_name": "<", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 324}, {"operation_name": "++", "type_lhs": "int", "type_rhs": "", "type_result": "int", "count": 324}, {"operation_name": "=", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 37}, {"operation_name": "=", "type_lhs": "volatile float", "type_rhs": "float", "type_result": "float", "count": 360}, {"operation_name": "/", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 360}, {"operation_name": "+", "type_lhs": "float", "type_rhs": "float", "type_result": "float", "count": 324}, {"operation_name": "*", "type_lhs": "float", "type_rhs": "float", "type_result": "float", "count": 324}, {"operation_name": "subscript", "type_lhs": "const float *", "type_rhs": "int", "type_result": "const float", "count": 324}, {"operation_name": "+", "type_lhs": "unsigned int", "type_rhs": "unsigned int", "type_result": "unsigned int", "count": 288}, {"operation_name": "subscript", "type_lhs": "const unsigned int *", "type_rhs": "int", "type_result": "const unsigned int", "count": 612}, {"operation_name": "-", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 288}, {"operation_name": "+", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 612}, {"operation_name": "subscript", "type_lhs": "volatile float *", "type_rhs": "int", "type_result": "volatile float", "count": 36}]}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
int main()
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 0; i++)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
{"for_loop.c": [{"operation_name": "<", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 0}, {"operation_name": "++", "type_lhs": "int", "type_rhs": "", "type_result": "int", "count": 0}, {"operation_name": "=", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 1}]}
|
|
||||||
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
//#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
// TODO: stddef.h not found.
|
|
||||||
|
|
||||||
int main(){
|
int gauss_blur(){
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
{"gauss_blur.c": [{"operation_name": "=", "type_lhs": "unsigned char *", "type_rhs": "unsigned char *", "type_result": "unsigned char *", "count": 4}, {"function_name": "malloc", "call_result_type": "void *", "count": 6}, {"operation_name": "*", "type_lhs": "unsigned long", "type_rhs": "unsigned long", "type_result": "unsigned long", "count": 6}, {"operation_name": "*", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 36868}, {"operation_name": "=", "type_lhs": "unsigned char **", "type_rhs": "unsigned char **", "type_result": "unsigned char **", "count": 2}, {"operation_name": "=", "type_lhs": "unsigned char", "type_rhs": "unsigned char", "type_result": "unsigned char", "count": 5000}, {"operation_name": "subscript", "type_lhs": "unsigned char *", "type_rhs": "int", "type_result": "unsigned char", "count": 41864}, {"operation_name": "==", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 18}, {"operation_name": "<", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 18824}, {"operation_name": "++", "type_lhs": "int", "type_rhs": "", "type_result": "int", "count": 69512}, {"operation_name": "=", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 18820}, {"operation_name": "-", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 50688}, {"operation_name": "<=", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 50688}, {"operation_name": "-", "type_lhs": "int", "type_rhs": "", "type_result": "int", "count": 18432}, {"operation_name": "||", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 36864}, {"operation_name": "!=", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 73728}, {"operation_name": "=", "type_lhs": "char", "type_rhs": "char", "type_result": "char", "count": 36864}, {"function_name": "abs", "call_result_type": "int", "count": 36864}, {"operation_name": "+", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 110592}, {"operation_name": ">", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 8680}, {"function_name": "free", "call_result_type": "void", "count": 4}]}
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
int a, b, c;
|
|
||||||
b = 10;
|
|
||||||
c = 15;
|
|
||||||
|
|
||||||
|
|
||||||
// F
|
|
||||||
if (c == 10)
|
|
||||||
{
|
|
||||||
a = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
// F
|
|
||||||
if (c == 10)
|
|
||||||
{
|
|
||||||
a = 10;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
a = 15;
|
|
||||||
}
|
|
||||||
|
|
||||||
// F T
|
|
||||||
if (c == 10 || b == 10)
|
|
||||||
{
|
|
||||||
a = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
// T T (not taken)
|
|
||||||
if (c == 15 || b == 10)
|
|
||||||
{
|
|
||||||
a = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
// T T
|
|
||||||
if (c == 15 && b == 10)
|
|
||||||
{
|
|
||||||
a = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
// T F
|
|
||||||
if (c == 15 && b == 15)
|
|
||||||
{
|
|
||||||
a = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
// F T
|
|
||||||
if (c == 10 && b == 15)
|
|
||||||
{
|
|
||||||
a = 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -17,12 +17,12 @@ int main(void)
|
|||||||
{
|
{
|
||||||
int m, n, p;
|
int m, n, p;
|
||||||
volatile UInt16 m3[3][5];
|
volatile UInt16 m3[3][5];
|
||||||
for(m = 0; m < 3; m++) // 1 + 3 * 2 // 3 * 3
|
for(m = 0; m < 3; m++)
|
||||||
{
|
{
|
||||||
for(p = 0; p < 5; p++) // 3 + 15 * 2 // 15 * 3
|
for(p = 0; p < 5; p++)
|
||||||
{
|
{
|
||||||
m3[m][p] = 0; // 15: BasicOperation(operation_name='=', type_lhs='unsigned short', type_rhs='unsigned short', type_result='unsigned short')
|
m3[m][p] = 0;
|
||||||
for(n = 0; n < 4; n++) // 15 + 60 * 2 // 60 * 3
|
for(n = 0; n < 4; n++)
|
||||||
{
|
{
|
||||||
m3[m][p] += m1[m][n] * m2[n][p];
|
m3[m][p] += m1[m][n] * m2[n][p];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
{"matrix.c": [{"operation_name": "<", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 78}, {"operation_name": "++", "type_lhs": "int", "type_rhs": "", "type_result": "int", "count": 78}, {"operation_name": "=", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 19}, {"operation_name": "=", "type_lhs": "unsigned short", "type_rhs": "unsigned short", "type_result": "unsigned short", "count": 15}, {"operation_name": "subscript", "type_lhs": "volatile UInt16 *", "type_rhs": "int", "type_result": "unsigned short", "count": 75}, {"operation_name": "subscript", "type_lhs": "volatile UInt16 (*)[5]", "type_rhs": "int", "type_result": "volatile UInt16 [5]", "count": 75}, {"operation_name": "*", "type_lhs": "int", "type_rhs": "int", "type_result": "int", "count": 60}, {"operation_name": "subscript", "type_lhs": "const UInt16 *", "type_rhs": "int", "type_result": "unsigned short", "count": 120}, {"operation_name": "subscript", "type_lhs": "const UInt16 (*)[4]", "type_rhs": "int", "type_result": "const UInt16 [4]", "count": 60}, {"operation_name": "subscript", "type_lhs": "const UInt16 (*)[5]", "type_rhs": "int", "type_result": "const UInt16 [5]", "count": 60}]}
|
|
||||||
17
testcases/stuff.h
Normal file
17
testcases/stuff.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// Created by erki on 23.02.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef C_ANALYZER_STUFF_H
|
||||||
|
#define C_ANALYZER_STUFF_H
|
||||||
|
|
||||||
|
void f()
|
||||||
|
{
|
||||||
|
int a = 4;
|
||||||
|
int b = 6;
|
||||||
|
|
||||||
|
int c = a + b;
|
||||||
|
(void)c;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //C_ANALYZER_STUFF_H
|
||||||
Loading…
x
Reference in New Issue
Block a user