Commit dee77e5f authored by Dr. Michael Petter's avatar Dr. Michael Petter

initial

parents
Pipeline #1160 failed with stages
in 1 second
#Mac specific
*.DS_Store
#Cmake Build folders
release
Release
RelWithDebInfo
**/*~
debug
Debug
build
Build
.build
output
# env config file
.config
# KDevelop
*.kdev4
# CLion
.idea
cmake-build-debug
# Visual Studio Code
.vscode
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
# llvm
*.ll
*.bc
# Jupyter notebook checkpoints
.ipynb_checkpoints
# If we don't need RTTI or EH, there's no reason to export anything
# from the hello plugin.
#if( NOT LLVM_REQUIRES_RTTI )
# if( NOT LLVM_REQUIRES_EH )
# set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Hello.exports)
# endif()
#endif()
if(WIN32 OR CYGWIN)
set(LLVM_LINK_COMPONENTS Core Support)
endif()
add_llvm_loadable_module( llvm-pain
src/fixpoint.cpp
src/fixpoint.h
src/value_set.cpp
src/value_set.h
src/simple_interval.cpp
src/simple_interval.h
DEPENDS
intrinsics_gen
PLUGIN_TOOL
opt
)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org>
# Program Optimization Lab 2018
Implements an LLVM analysis pass using abstract interpretation.
## Build
Get the LLVM source code from [here](http://releases.llvm.org/download.html). Then get clang as well, into `llvm/tools`. Create a build directory somewhere, initialise CMake, and build. For example
# From your llvm-7.0.0-src, or whatever the version is now
cd ..
mkdir llvm_build
cd llvm_build
cmake ../llvm-?.?.?-src -DLLVM_TARGETS_TO_BUILD=X86
make -j2
The parallel make may run out of memory at the end. You can restart it sequentially by issuing another `make`.
Now we can initalise the repository.
cd ..
git clone ssh://git@github.com/PUT/THE/CORRECT/REPOSITORY/IN/HERE.git
cd PUT/THE/CORRECT/REPOSITORY/IN/HERE
python3 init.py
The script should be able to find your LLVM and clang. If it is not, you need to specify them by hand.
At last, let us compile and run the samples.
python3 run.py --make
If there are errors regarding missing header files, you probably need to rebuild llvm.
## Useful things
The `run.py` script contains everything, up to and including the kitchen sink. It can run the samples, build, run the debugger, as well as build and run the tests. Just read its help message to get all the good stuff. I want to highlight the `-n` option, which causes it to just print out the commands it would run. This is great to just copy-paste the relevant ones into your terminal (or IDE).
## Authors
* Ramona Brückl
* Philipp Czerner ([github](https://github.com/suyjuris/), [mail](mailto:philipp.czerner@nicze.de))
* Tim Gymnich
* Thomas Frank
### Authors of previous semesters
* Julian Erhard
* Jakob Gottfriedsen
* Peter Munch
* Alexander Roschlaub
* Michael B. Schwarz
#!/usr/bin/python3
# coding: utf-8
import argparse
import os
import subprocess
import sys
if sys.version_info[0] < 3:
print("Error: This script only supports Python 3")
sys.exit(5)
parser = argparse.ArgumentParser(description='Setup the project. This creates the necessary symbolic links in the LLVM source code and adds the entries into the right CMakeList.txt. Also initialises the configuration for the run.py script.')
parser.add_argument('--llvm-path', help='path to the LLVM build directory, containing a file bin/opt.')
parser.add_argument('--llvm-src', help='path to the LLVM source directory, containing lib/Analysis ')
parser.add_argument('--clang-path', help='path to the clang build direcotry, containing a file bin/clang')
args = parser.parse_args()
llvm_path = args.llvm_path
llvm_src = args.llvm_src
clang_path = args.clang_path
project_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
project_name = 'AbstractInterpretation'
cmake = 'cmake'
if llvm_path is None:
# Try to guess the correct path
d = os.path.abspath(project_dir)
while os.path.dirname(d) != d:
d = os.path.dirname(d)
for i in os.listdir(d):
if os.path.isfile(d + '/' + i + '/bin/opt'):
llvm_path = d + '/' + i
print('Auto-detecting llvm-path as ' + llvm_path)
break
if llvm_path is not None: break
else:
print('Error: No llvm-path specified (use --llvm-path)')
parser.print_help()
sys.exit(1)
if llvm_src is None:
# Try to guess the correct path
d = os.path.abspath(project_dir)
while os.path.dirname(d) != d:
d = os.path.dirname(d)
for i in os.listdir(d):
if os.path.isfile(d + '/' + i + '/cmake_install.cmake'):
continue
if os.path.isdir(d + '/' + i + '/lib/Analysis'):
llvm_src = d + '/' + i
print('Auto-detecting llvm-src as ' + llvm_src)
break
if llvm_src is not None: break
else:
print('Error: No llvm-src specified (use --llvm-src)')
parser.print_help()
sys.exit(1)
if clang_path is None:
clang_path = llvm_path
print('clang-path not specified, defaulting to ' + clang_path)
opt = llvm_path + '/bin/opt'
llvm_dest = llvm_src + '/lib/Analysis'
clang = clang_path + '/bin/clang'
if not os.path.isfile(opt):
print('Error: no opt exists at ' + opt + ' (maybe you forgot to build LLVM?)')
sys.exit(2)
if not os.path.isdir(llvm_dest):
print('Error: directory does not exist, at ' + llvm_dest)
sys.exit(2)
if not os.path.isfile(clang):
print('Error: no clang exists at ' + clang)
sys.exit(2)
# Create the symbolic link in the LLVM sources
try:
link_name = llvm_dest + '/' + project_name
os.symlink(project_dir, link_name, target_is_directory=True)
print('Created symbolic link from %s to %s' % (link_name, project_dir))
except FileExistsError:
print('Symlink already exists')
# Write the configuration for the run.py script
config_file_name = project_dir + '/.config';
config_file = open(config_file_name, 'w')
config_file.write(llvm_src+'\n'+llvm_path+'\n'+clang_path+'\n')
config_file.close()
print('Wrote configuration to %s' % (config_file_name,))
# Adjust CMakeLists.txt
cmake_file_name = llvm_dest + '/CMakeLists.txt'
line_to_insert = 'add_subdirectory(%s)\n' % (project_name,)
cmake_file = open(cmake_file_name, 'r')
lines = cmake_file.readlines()
needs_changes = line_to_insert not in lines
cmake_file.close()
if needs_changes:
cmake_file = open(cmake_file_name, 'a')
cmake_file.write('\n' + line_to_insert)
cmake_file.close()
print('CMakeLists.txt modified, at %s' % (cmake_file_name,))
# Also regenerate the CMake cache
print('Rebuilding cmake cache')
subprocess.run([cmake, llvm_path], check=True)
else:
print('CMakeLists.txt is fine')
#!/usr/bin/python3
# coding: utf-8
import argparse
import os
import platform
import shlex
import subprocess
import sys
if sys.version_info[0] < 3:
print("Error: This script only supports Python 3")
sys.exit(5)
project_dir = os.path.abspath(os.path.dirname(sys.argv[0]))
os.chdir(project_dir)
if not os.path.isfile(".config"):
print("No config file was found. Please run init.py first!")
sys.exit(-1)
config_file = open(".config", "r")
lines = config_file.readlines()
llvm_path = lines[1].strip()
clang_path = lines[2].strip()
config_file.close()
opt = llvm_path + '/bin/opt'
llvm_dis = llvm_path + '/bin/llvm-dis'
llvm_config = llvm_path + '/bin/llvm-config'
clang = clang_path + '/bin/clang'
cmake = 'cmake'
gdb = 'gdb'
lldb = 'lldb'
CXX = os.environ.get('CXX', 'c++')
if not os.path.isfile(opt):
print('Error: no opt exists at ' + opt + ' (maybe you forgot to build LLVM?)')
sys.exit(2)
if not os.path.isfile(llvm_dis):
print('Error: no llvm-dis exists at ' + llvm_dis + ' (maybe you forgot to build LLVM?)')
sys.exit(2)
if not os.path.isfile(clang):
print('Error: no clang exists at ' + clang)
sys.exit(2)
if platform.system() == 'Linux':
libeext = '.so'
elif platform.system() == 'Windows':
libeext = '.dll'
print('Error: Windows is not supported. (You can try to delete this error and proceed at your own risk.')
sys.exit(4)
elif platform.system() == 'Darwin':
libeext = '.dylib'
else:
print('Error: Unknown platform ' + platform.system())
sys.exit(4)
pass_lib = llvm_path + "/lib/llvm-pain" + libeext
pass_name = "painpass"
make_target = "llvm-pain"
samples = project_dir + '/samples'
def main():
def run(arg, cwd=None, redirect=None):
if not args.only_print:
try:
if redirect:
f = open(redirect, 'w')
subprocess.run(arg, cwd=cwd, stdout=f, stderr=f, check=True)
f.close()
else:
subprocess.run(arg, cwd=cwd, check=True)
except subprocess.CalledProcessError as e:
print('Error: while executing ' + str(e.cmd))
if redirect:
f.close()
print(open(redirect, 'r').read())
sys.exit(3)
else:
cmd = ' '.join(shlex.quote(i) for i in arg)
if redirect:
cmd += ' > %s 2>&1' % (shlex.quote(redirect),)
if cwd is None:
print(' ' + cmd)
else:
print(' ( cd %s && %s )' % (shlex.quote(cwd), cmd))
parser = argparse.ArgumentParser()
parser.add_argument("file", help="run only the specfied files", nargs='*')
parser.add_argument("-n", dest='only_print', help="only print the commands, do not execute anything", action="store_true")
parser.add_argument("-v", dest='show_output', help="show output on stdout", action="store_true")
parser.add_argument("--cfg", dest='view_cfg', help="show llvm control flow graph", action="store_true")
parser.add_argument("--make", dest='do_make', help="call make before executing the script", action="store_true")
parser.add_argument("--only-make", dest='do_make_only', help="only call make, do not execute any samples", action="store_true")
parser.add_argument("--gdb", dest='do_gdb', help="open the gdb debugger for the specified file", action="store_true") # might not work with mac OS try lldb
parser.add_argument("--lldb", dest='do_lldb', help="open the lldb debugger for the specified file", action="store_true")
parser.add_argument("--run-test", dest='run_test', help="run the test for SimpleInterval", action="store_true")
parser.add_argument("--use-cxx", metavar='path', dest='use_cxx', help="use as c++ compiler when building the test")
args = parser.parse_args()
# If no files are specified, set it to all .c files in current directory
files = args.file
if args.run_test:
if files:
print('Error: you are trying to both run the test and a file. This does not really make sense.')
sys.exit(4)
elif args.do_gdb:
if len(files) != 1:
print('Error: you are trying to run the debugger on multiple files. This does not really make sense, just specify a single one.')
sys.exit(4)
elif args.do_make_only:
args.do_make = True
files = []
args.run_test = False
elif not files:
files = [i for i in os.listdir(samples) if i.endswith('.c')]
if args.do_make:
print("Building %s..." % (make_target,))
run([cmake, '--build', llvm_path, '--target', make_target])
if not os.path.isfile(pass_lib):
print('Error: Could not find shared library ' + pass_lib)
print('Please build the project (for example by running this script with the option --make')
sys.exit(7)
os.makedirs('output', exist_ok=True)
for fname in files:
f_orig = 'samples/%s' % (fname,)
f_bc = 'output/%s-tmp.bc' % (fname,)
f_optbc = 'output/%s.bc' % (fname,)
f_optll = 'output/%s.ll' % (fname,)
f_out = 'output/%s.out' % (fname,)
if not os.path.isfile(f_orig):
print("Error: " + f_orig +" not found!")
continue
print("Processing file " + fname + " ...")
run([clang, '-O0', '-emit-llvm', f_orig, '-Xclang', '-disable-O0-optnone', '-c', '-o', f_bc])
run([opt, '-mem2reg', f_bc, '-o', f_optbc])
run([llvm_dis, f_optbc, '-o', f_optll])
run(['rm', f_bc, f_optbc])
redir = None if args.show_output else f_out
args_add = []
if args.view_cfg:
args_add.append('--view-cfg')
base_args = ['-load', pass_lib, '-'+pass_name, '-S'] + args_add + ['-o', '/dev/null', f_optll]
if not args.do_gdb:
run([opt] + base_args, redirect=redir)
else:
break_at = 'pcpo::AbstractInterpretationPass::runOnModule(llvm::Module&)'
if not args.only_print:
print('In a moment, gdb is going to read in the symbols of opt. As you might notice, that takes a long time. So, here is a tip: Just restart the program using r (no need to specify arguments). Even if you rebuild the project, that is in a shared library and will thus be reloaded the next time you start the program.')
run([gdb, '-q', opt, '-ex', 'r ' + ' '.join(map(shlex.quote, base_args))])
if not args.do_lldb:
run([opt] + base_args, redirect=redir)
else:
break_at = 'pcpo::AbstractInterpretationPass::runOnModule(llvm::Module&)'
run([lldb, opt, '--', ' '.join(map(shlex.quote, base_args))])
if args.run_test:
if not os.path.isfile(llvm_config):
print('Error: no llvm-config exists at ' + llvm_config + ' (maybe you forgot to build LLVM?)')
sys.exit(2)
os.makedirs('build', exist_ok=True)
cxx = CXX
if args.use_cxx is not None:
cxx = args.use_cxx
print('Info: Building the test using %s' % (cxx,))
cxxflags = subprocess.run([llvm_config, '--cxxflags'], stdout=subprocess.PIPE).stdout.decode('ascii').split()
ldflags = subprocess.run([llvm_config, '--ldflags' ], stdout=subprocess.PIPE).stdout.decode('ascii').split()
libs = subprocess.run([llvm_config, '--libs', 'analysis'], stdout=subprocess.PIPE).stdout.decode('ascii').split()
if platform.system() == 'Darwin':
libs += '-lz -ldl -lpthread -lm -lcurses'.split()
else:
libs += '-lz -lrt -ldl -ltinfo -lpthread -lm'.split()
run([cxx, 'test/simple_interval_test.cpp', 'src/simple_interval.cpp', '-Isrc', '-fmax-errors=2'] + cxxflags
+ ['-o', 'build/SimpleIntervalTest'] + ldflags + libs)
try:
run(['build/SimpleIntervalTest'])
except KeyboardInterrupt:
pass
if __name__ == "__main__":
main()
int test() {
int a = 1; a++; // a={2}
int b = 2; b++; // b={3}
int c;
c += 1; // c=T
if(c == a){ // c=a={2}
c += 1; // c={3}
a = c; // a={3}
}
// a={2,3}
return a + b; // ret={5,6}
}
\ No newline at end of file
int test() {
int a = 1; a++; // a={2}
int b = 2; b++; // b={3}
int c = 3; c++; // c={4}
if(c == a){ // bottom
c += 1; //
a = c; //
}
// a={2}
return a + b; // ret={5}
}
\ No newline at end of file
int test() {
int a = 1; a++; // a={2}
int b = 2; b++; // b={3}
int c = 3; c++; // c={4}
if(c != a){
c += 1; // c={5}
a = c; // a={5}
}
// a={5}
return a + b; // ret={8}
}
\ No newline at end of file
int test() {
int a = 1; a++; // a={2}
int b = 2; b++; // b={3}
int c = 3; c++; // c={4}
if(c <= a){ // bottom
c += 1; //
a = c; //
}
// a={12}
return a + b; // ret={5}
}
\ No newline at end of file
int main(int argc, char** argv) {
int a = argc % 7 + 10;
while (a != 20) ++a;
int b = a;
int c;
if (b < 20) {
c = argc % 355;
} else {
c = 5;
}
return c;
}
#include <stdio.h>
// test program:
// comparison of two variables
int main(int argc, char const *argv[]) {
int x, y;
if (argc == 0)
x = 1;
else
x = 3;
if (argc == 0)
y = 2;
else
y = 4;
// at this point: x={1,3} and y={2,4}
if (x < y)
// at this point: x={1,3} and y={2,4}
printf("%d\n", x);
else
// at this point: x={3} and y{2}
printf("%d\n", y);
}
#include <stdio.h>
// test program:
// comparison of two variables
int main(int argc, char const *argv[]) {
int x, y;
// perform dummy intialization of values
if (argc == 0)
x = 1;
else
x = 3;
if (argc == 0)
y = 0;
else
y = 4;
// at this point x={1,2} y={0,4}
if (x < y)
// at this point x={1,3} and y={4}
if (y == 0)
// branch is never entered
printf("%d\n", x);
}
/*
* Copyright (c) 2009, eagletmt
* Released under the MIT License <http://opensource.org/licenses/mit-license.php>
*/
#include <stdio.h>
#define N 1000
#define Q 10000000000ULL
int main(void)
{
unsigned long long rem = 0;
unsigned i;
for (i = 1; i < N; i++) {
unsigned long long r = 1;
unsigned j;
for (j = 0; j < 15; j++) {
r = (r * i) % Q;
}
rem = (rem + r) % Q;
}
printf("%llu\n", rem);
return 0;
}
/*
* Copyright (c) 2009, eagletmt
* Released under the MIT License <http://opensource.org/licenses/mit-license.php>
*/
#include <stdio.h>
static unsigned days(unsigned y, unsigned m);
int main(void)
{
unsigned year, wday = 0, sun = 0, mon;
for (year = 1901; year <= 2000; year++) {
for (mon = 1; mon <= 12; mon++) {
if (wday == 5) {
/* 1901-01-01 is Tuesday, so wday == 5 means Sunday */
sun++;
}
wday = (wday + days(year, mon))%7;
}
}
printf("%d\n", sun);
return 0;
}
unsigned days(unsigned y, unsigned m)
{
switch (m) {
case 2:
if ((y%4 == 0 && y%100 != 0) || y%400 == 0) {
/* leap year */
return 29;
}
else {
return 28;
}
case 4:
case 6:
case 9:
case 11:
return 30;
default:
return 31;
}
}
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[]) {
unsigned a = 0;
unsigned b = 12;
while (a < b) {
a+=4;
b-=2;
}
unsigned c = rand();
if(a>6 && b<6){
switch (a) {
case 6:
b = 99;
break;
case 12:
case 13:
b = a*2;
break;
default:
c = c%18;
}
} else {
a = 88;
}
printf("%d\n", a);
printf("%d\n", b);
printf("%d\n", c);
}
#include <stdio.h>
#include <stdlib.h>
// test program:
// simple loop
int main(int argc, char const *argv[]) {
int x = 42;
//x += 7;
int y = 2;
for(int i=0; i<y;i++){