├── .gitignore ├── LICENSE ├── Makefile.am ├── Makefile.in ├── README ├── README.md ├── build-aux ├── compile ├── depcomp ├── install-sh └── missing ├── configure ├── configure.ac ├── doc ├── design.tex ├── doxygen-config.in └── uops.tex ├── doxygen.mk.am ├── doxygen.mk.in ├── libraries ├── cppformat │ ├── format.cc │ └── format.h └── cppinput │ └── cppinput.hpp ├── m4 ├── ax_cxx_compile_stdcxx_11.m4 ├── ax_mpi.m4 └── ax_prog_doxygen.m4 ├── src ├── GenericTargetMachine.hpp ├── Instruction.hpp ├── TargetMachine.hpp ├── TargetMachineWithFlags.hpp ├── algorithms │ ├── bruteforce.hpp │ ├── bruteforceByCost.hpp │ ├── canonicalIterator.hpp │ ├── canonicalIteratorBasic.cpp │ ├── canonicalIteratorBasic.hpp │ ├── canonicalIteratorGeneric.cpp │ ├── canonicalIteratorGeneric.hpp │ ├── canonicalIteratorLiveness.cpp │ ├── canonicalIteratorLiveness.hpp │ ├── constantIterator.cpp │ ├── constantIterator.hpp │ └── test.hpp ├── frontend.hpp ├── frontends │ ├── avr.hpp │ └── avr.yml ├── generate.py ├── main.cpp ├── main_parallel.cpp ├── parallel │ └── mpi.hpp ├── slots.hpp ├── utility.cpp └── utility.hpp └── tests ├── avr_instruction.cpp ├── bruteforce.cpp ├── bruteforceByCost.cpp ├── canonical_slots.cpp ├── canonical_speed.cpp ├── canonical_speed_full.cpp ├── data ├── long_1.csv ├── long_2.csv ├── sparse_4.csv ├── sparse_5.csv ├── standard_1.csv └── standard_2.csv ├── frontend.cpp ├── slots.cpp ├── test.cpp ├── test_main.cpp └── utility.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | *.test 31 | 32 | # Debug files 33 | *.dSYM/ 34 | 35 | # 36 | .deps 37 | .dirstamp 38 | Makefile 39 | *.mk 40 | 41 | *_gen.hpp 42 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | LIBRARIES_DIR=libraries 3 | LIBRARIES_SRCLIST=libraries/cppformat/format.cc 4 | 5 | TK_SRCLIST= ${LIBRARIES_SRCLIST} \ 6 | src/utility.cpp \ 7 | src/algorithms/canonicalIteratorBasic.cpp \ 8 | src/algorithms/canonicalIteratorGeneric.cpp \ 9 | src/algorithms/canonicalIteratorLiveness.cpp \ 10 | src/algorithms/constantIterator.cpp 11 | 12 | ############################################################################## 13 | 14 | ACLOCAL_AMFLAGS= -I m4 15 | AM_CPPFLAGS= -I $(abs_srcdir)/$(LIBRARIES_DIR) \ 16 | -I $(abs_srcdir)/src \ 17 | -std=c++11 18 | AM_CXXFLAGS= -O3 -mtune=native 19 | 20 | ############################################################################## 21 | ## Autogenerated files 22 | 23 | # TODO: these should probably be built in the build directory? 24 | BUILT_SOURCES=$(abs_srcdir)/src/frontends/avr_gen.hpp 25 | 26 | %_gen.hpp: %.yml 27 | python $(abs_srcdir)/src/generate.py $< $@ 28 | 29 | ############################################################################## 30 | 31 | bin_PROGRAMS=gsotk tests/test 32 | gsotk_SOURCES=src/main.cpp $(TK_SRCLIST) 33 | 34 | ############################################################################## 35 | 36 | tests_test_CPPFLAGS=$(AM_CPPFLAGS) 37 | tests_test_DEPENDENCIES=tests/data/long_1.csv 38 | tests_test_SOURCES=tests/test_main.cpp \ 39 | tests/avr_instruction.cpp \ 40 | tests/slots.cpp \ 41 | tests/bruteforce.cpp \ 42 | tests/bruteforceByCost.cpp \ 43 | tests/test.cpp \ 44 | tests/canonical_slots.cpp \ 45 | tests/frontend.cpp \ 46 | tests/utility.cpp \ 47 | $(TK_SRCLIST) 48 | tests_tests_CXXFLAGS=-O0 49 | 50 | test: tests/test 51 | cd tests && ./test 52 | ############################################################################## 53 | 54 | if HAVE_MPI 55 | bin_PROGRAMS += gsotk_parallel 56 | 57 | gsotk_parallel_SOURCES= src/main_parallel.cpp $(TK_SRCLIST) 58 | endif 59 | 60 | ############################################################################## 61 | 62 | TEXPDF= 63 | PDFLATEX_FLAGS= -shell-escape 64 | 65 | if HAVE_PDFLATEX 66 | TEXPDF+=doc/design.pdf 67 | endif 68 | 69 | doc: doxygen-run $(TEXPDF) 70 | make doxygen-pdf 71 | 72 | doc/%.pdf: $(abs_srcdir)/doc/%.tex 73 | cd $(dir $@) && $(PDFLATEX) $(PDFLATEX_FLAGS) $< 74 | cd $(dir $@) && $(PDFLATEX) $(PDFLATEX_FLAGS) $< 75 | 76 | include doxygen.mk.am 77 | 78 | MOSTLYCLEANFILES=$(DX_CLEANFILES) $(TEXPDF) 79 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | README.md -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GSOv2: The Superoptimization Toolkit 2 | 3 | This respository holds the superoptimizer toolkit, a successor to the GNU Superoptimizer. Currently much of this is a work-in-progress and subject to change. A basic example of the superoptimizer can be found in `src/main.cpp`. 4 | 5 | ## Documentation 6 | 7 | The documentation is also a work-in-progress, but there exists the start of a design document (LaTeX), which can be built with the `make doc` command. 8 | 9 | ## Requirements 10 | 11 | Python: 12 | 13 | - pyyaml 14 | - docopt 15 | 16 | C++: 17 | 18 | - A C++11 compiler 19 | - boost algorithm 20 | - boost unit test (for the tests) 21 | -------------------------------------------------------------------------------- /build-aux/compile: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Wrapper for compilers which do not understand '-c -o'. 3 | 4 | scriptversion=2012-10-14.11; # UTC 5 | 6 | # Copyright (C) 1999-2013 Free Software Foundation, Inc. 7 | # Written by Tom Tromey . 8 | # 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | # This file is maintained in Automake, please report 28 | # bugs to or send patches to 29 | # . 30 | 31 | nl=' 32 | ' 33 | 34 | # We need space, tab and new line, in precisely that order. Quoting is 35 | # there to prevent tools from complaining about whitespace usage. 36 | IFS=" "" $nl" 37 | 38 | file_conv= 39 | 40 | # func_file_conv build_file lazy 41 | # Convert a $build file to $host form and store it in $file 42 | # Currently only supports Windows hosts. If the determined conversion 43 | # type is listed in (the comma separated) LAZY, no conversion will 44 | # take place. 45 | func_file_conv () 46 | { 47 | file=$1 48 | case $file in 49 | / | /[!/]*) # absolute file, and not a UNC file 50 | if test -z "$file_conv"; then 51 | # lazily determine how to convert abs files 52 | case `uname -s` in 53 | MINGW*) 54 | file_conv=mingw 55 | ;; 56 | CYGWIN*) 57 | file_conv=cygwin 58 | ;; 59 | *) 60 | file_conv=wine 61 | ;; 62 | esac 63 | fi 64 | case $file_conv/,$2, in 65 | *,$file_conv,*) 66 | ;; 67 | mingw/*) 68 | file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` 69 | ;; 70 | cygwin/*) 71 | file=`cygpath -m "$file" || echo "$file"` 72 | ;; 73 | wine/*) 74 | file=`winepath -w "$file" || echo "$file"` 75 | ;; 76 | esac 77 | ;; 78 | esac 79 | } 80 | 81 | # func_cl_dashL linkdir 82 | # Make cl look for libraries in LINKDIR 83 | func_cl_dashL () 84 | { 85 | func_file_conv "$1" 86 | if test -z "$lib_path"; then 87 | lib_path=$file 88 | else 89 | lib_path="$lib_path;$file" 90 | fi 91 | linker_opts="$linker_opts -LIBPATH:$file" 92 | } 93 | 94 | # func_cl_dashl library 95 | # Do a library search-path lookup for cl 96 | func_cl_dashl () 97 | { 98 | lib=$1 99 | found=no 100 | save_IFS=$IFS 101 | IFS=';' 102 | for dir in $lib_path $LIB 103 | do 104 | IFS=$save_IFS 105 | if $shared && test -f "$dir/$lib.dll.lib"; then 106 | found=yes 107 | lib=$dir/$lib.dll.lib 108 | break 109 | fi 110 | if test -f "$dir/$lib.lib"; then 111 | found=yes 112 | lib=$dir/$lib.lib 113 | break 114 | fi 115 | if test -f "$dir/lib$lib.a"; then 116 | found=yes 117 | lib=$dir/lib$lib.a 118 | break 119 | fi 120 | done 121 | IFS=$save_IFS 122 | 123 | if test "$found" != yes; then 124 | lib=$lib.lib 125 | fi 126 | } 127 | 128 | # func_cl_wrapper cl arg... 129 | # Adjust compile command to suit cl 130 | func_cl_wrapper () 131 | { 132 | # Assume a capable shell 133 | lib_path= 134 | shared=: 135 | linker_opts= 136 | for arg 137 | do 138 | if test -n "$eat"; then 139 | eat= 140 | else 141 | case $1 in 142 | -o) 143 | # configure might choose to run compile as 'compile cc -o foo foo.c'. 144 | eat=1 145 | case $2 in 146 | *.o | *.[oO][bB][jJ]) 147 | func_file_conv "$2" 148 | set x "$@" -Fo"$file" 149 | shift 150 | ;; 151 | *) 152 | func_file_conv "$2" 153 | set x "$@" -Fe"$file" 154 | shift 155 | ;; 156 | esac 157 | ;; 158 | -I) 159 | eat=1 160 | func_file_conv "$2" mingw 161 | set x "$@" -I"$file" 162 | shift 163 | ;; 164 | -I*) 165 | func_file_conv "${1#-I}" mingw 166 | set x "$@" -I"$file" 167 | shift 168 | ;; 169 | -l) 170 | eat=1 171 | func_cl_dashl "$2" 172 | set x "$@" "$lib" 173 | shift 174 | ;; 175 | -l*) 176 | func_cl_dashl "${1#-l}" 177 | set x "$@" "$lib" 178 | shift 179 | ;; 180 | -L) 181 | eat=1 182 | func_cl_dashL "$2" 183 | ;; 184 | -L*) 185 | func_cl_dashL "${1#-L}" 186 | ;; 187 | -static) 188 | shared=false 189 | ;; 190 | -Wl,*) 191 | arg=${1#-Wl,} 192 | save_ifs="$IFS"; IFS=',' 193 | for flag in $arg; do 194 | IFS="$save_ifs" 195 | linker_opts="$linker_opts $flag" 196 | done 197 | IFS="$save_ifs" 198 | ;; 199 | -Xlinker) 200 | eat=1 201 | linker_opts="$linker_opts $2" 202 | ;; 203 | -*) 204 | set x "$@" "$1" 205 | shift 206 | ;; 207 | *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) 208 | func_file_conv "$1" 209 | set x "$@" -Tp"$file" 210 | shift 211 | ;; 212 | *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) 213 | func_file_conv "$1" mingw 214 | set x "$@" "$file" 215 | shift 216 | ;; 217 | *) 218 | set x "$@" "$1" 219 | shift 220 | ;; 221 | esac 222 | fi 223 | shift 224 | done 225 | if test -n "$linker_opts"; then 226 | linker_opts="-link$linker_opts" 227 | fi 228 | exec "$@" $linker_opts 229 | exit 1 230 | } 231 | 232 | eat= 233 | 234 | case $1 in 235 | '') 236 | echo "$0: No command. Try '$0 --help' for more information." 1>&2 237 | exit 1; 238 | ;; 239 | -h | --h*) 240 | cat <<\EOF 241 | Usage: compile [--help] [--version] PROGRAM [ARGS] 242 | 243 | Wrapper for compilers which do not understand '-c -o'. 244 | Remove '-o dest.o' from ARGS, run PROGRAM with the remaining 245 | arguments, and rename the output as expected. 246 | 247 | If you are trying to build a whole package this is not the 248 | right script to run: please start by reading the file 'INSTALL'. 249 | 250 | Report bugs to . 251 | EOF 252 | exit $? 253 | ;; 254 | -v | --v*) 255 | echo "compile $scriptversion" 256 | exit $? 257 | ;; 258 | cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) 259 | func_cl_wrapper "$@" # Doesn't return... 260 | ;; 261 | esac 262 | 263 | ofile= 264 | cfile= 265 | 266 | for arg 267 | do 268 | if test -n "$eat"; then 269 | eat= 270 | else 271 | case $1 in 272 | -o) 273 | # configure might choose to run compile as 'compile cc -o foo foo.c'. 274 | # So we strip '-o arg' only if arg is an object. 275 | eat=1 276 | case $2 in 277 | *.o | *.obj) 278 | ofile=$2 279 | ;; 280 | *) 281 | set x "$@" -o "$2" 282 | shift 283 | ;; 284 | esac 285 | ;; 286 | *.c) 287 | cfile=$1 288 | set x "$@" "$1" 289 | shift 290 | ;; 291 | *) 292 | set x "$@" "$1" 293 | shift 294 | ;; 295 | esac 296 | fi 297 | shift 298 | done 299 | 300 | if test -z "$ofile" || test -z "$cfile"; then 301 | # If no '-o' option was seen then we might have been invoked from a 302 | # pattern rule where we don't need one. That is ok -- this is a 303 | # normal compilation that the losing compiler can handle. If no 304 | # '.c' file was seen then we are probably linking. That is also 305 | # ok. 306 | exec "$@" 307 | fi 308 | 309 | # Name of file we expect compiler to create. 310 | cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` 311 | 312 | # Create the lock directory. 313 | # Note: use '[/\\:.-]' here to ensure that we don't use the same name 314 | # that we are using for the .o file. Also, base the name on the expected 315 | # object file name, since that is what matters with a parallel build. 316 | lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d 317 | while true; do 318 | if mkdir "$lockdir" >/dev/null 2>&1; then 319 | break 320 | fi 321 | sleep 1 322 | done 323 | # FIXME: race condition here if user kills between mkdir and trap. 324 | trap "rmdir '$lockdir'; exit 1" 1 2 15 325 | 326 | # Run the compile. 327 | "$@" 328 | ret=$? 329 | 330 | if test -f "$cofile"; then 331 | test "$cofile" = "$ofile" || mv "$cofile" "$ofile" 332 | elif test -f "${cofile}bj"; then 333 | test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" 334 | fi 335 | 336 | rmdir "$lockdir" 337 | exit $ret 338 | 339 | # Local Variables: 340 | # mode: shell-script 341 | # sh-indentation: 2 342 | # eval: (add-hook 'write-file-hooks 'time-stamp) 343 | # time-stamp-start: "scriptversion=" 344 | # time-stamp-format: "%:y-%02m-%02d.%02H" 345 | # time-stamp-time-zone: "UTC" 346 | # time-stamp-end: "; # UTC" 347 | # End: 348 | -------------------------------------------------------------------------------- /build-aux/missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common wrapper for a few potentially missing GNU programs. 3 | 4 | scriptversion=2013-10-28.13; # UTC 5 | 6 | # Copyright (C) 1996-2013 Free Software Foundation, Inc. 7 | # Originally written by Fran,cois Pinard , 1996. 8 | 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | if test $# -eq 0; then 28 | echo 1>&2 "Try '$0 --help' for more information" 29 | exit 1 30 | fi 31 | 32 | case $1 in 33 | 34 | --is-lightweight) 35 | # Used by our autoconf macros to check whether the available missing 36 | # script is modern enough. 37 | exit 0 38 | ;; 39 | 40 | --run) 41 | # Back-compat with the calling convention used by older automake. 42 | shift 43 | ;; 44 | 45 | -h|--h|--he|--hel|--help) 46 | echo "\ 47 | $0 [OPTION]... PROGRAM [ARGUMENT]... 48 | 49 | Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due 50 | to PROGRAM being missing or too old. 51 | 52 | Options: 53 | -h, --help display this help and exit 54 | -v, --version output version information and exit 55 | 56 | Supported PROGRAM values: 57 | aclocal autoconf autoheader autom4te automake makeinfo 58 | bison yacc flex lex help2man 59 | 60 | Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 61 | 'g' are ignored when checking the name. 62 | 63 | Send bug reports to ." 64 | exit $? 65 | ;; 66 | 67 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 68 | echo "missing $scriptversion (GNU Automake)" 69 | exit $? 70 | ;; 71 | 72 | -*) 73 | echo 1>&2 "$0: unknown '$1' option" 74 | echo 1>&2 "Try '$0 --help' for more information" 75 | exit 1 76 | ;; 77 | 78 | esac 79 | 80 | # Run the given program, remember its exit status. 81 | "$@"; st=$? 82 | 83 | # If it succeeded, we are done. 84 | test $st -eq 0 && exit 0 85 | 86 | # Also exit now if we it failed (or wasn't found), and '--version' was 87 | # passed; such an option is passed most likely to detect whether the 88 | # program is present and works. 89 | case $2 in --version|--help) exit $st;; esac 90 | 91 | # Exit code 63 means version mismatch. This often happens when the user 92 | # tries to use an ancient version of a tool on a file that requires a 93 | # minimum version. 94 | if test $st -eq 63; then 95 | msg="probably too old" 96 | elif test $st -eq 127; then 97 | # Program was missing. 98 | msg="missing on your system" 99 | else 100 | # Program was found and executed, but failed. Give up. 101 | exit $st 102 | fi 103 | 104 | perl_URL=http://www.perl.org/ 105 | flex_URL=http://flex.sourceforge.net/ 106 | gnu_software_URL=http://www.gnu.org/software 107 | 108 | program_details () 109 | { 110 | case $1 in 111 | aclocal|automake) 112 | echo "The '$1' program is part of the GNU Automake package:" 113 | echo "<$gnu_software_URL/automake>" 114 | echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" 115 | echo "<$gnu_software_URL/autoconf>" 116 | echo "<$gnu_software_URL/m4/>" 117 | echo "<$perl_URL>" 118 | ;; 119 | autoconf|autom4te|autoheader) 120 | echo "The '$1' program is part of the GNU Autoconf package:" 121 | echo "<$gnu_software_URL/autoconf/>" 122 | echo "It also requires GNU m4 and Perl in order to run:" 123 | echo "<$gnu_software_URL/m4/>" 124 | echo "<$perl_URL>" 125 | ;; 126 | esac 127 | } 128 | 129 | give_advice () 130 | { 131 | # Normalize program name to check for. 132 | normalized_program=`echo "$1" | sed ' 133 | s/^gnu-//; t 134 | s/^gnu//; t 135 | s/^g//; t'` 136 | 137 | printf '%s\n' "'$1' is $msg." 138 | 139 | configure_deps="'configure.ac' or m4 files included by 'configure.ac'" 140 | case $normalized_program in 141 | autoconf*) 142 | echo "You should only need it if you modified 'configure.ac'," 143 | echo "or m4 files included by it." 144 | program_details 'autoconf' 145 | ;; 146 | autoheader*) 147 | echo "You should only need it if you modified 'acconfig.h' or" 148 | echo "$configure_deps." 149 | program_details 'autoheader' 150 | ;; 151 | automake*) 152 | echo "You should only need it if you modified 'Makefile.am' or" 153 | echo "$configure_deps." 154 | program_details 'automake' 155 | ;; 156 | aclocal*) 157 | echo "You should only need it if you modified 'acinclude.m4' or" 158 | echo "$configure_deps." 159 | program_details 'aclocal' 160 | ;; 161 | autom4te*) 162 | echo "You might have modified some maintainer files that require" 163 | echo "the 'autom4te' program to be rebuilt." 164 | program_details 'autom4te' 165 | ;; 166 | bison*|yacc*) 167 | echo "You should only need it if you modified a '.y' file." 168 | echo "You may want to install the GNU Bison package:" 169 | echo "<$gnu_software_URL/bison/>" 170 | ;; 171 | lex*|flex*) 172 | echo "You should only need it if you modified a '.l' file." 173 | echo "You may want to install the Fast Lexical Analyzer package:" 174 | echo "<$flex_URL>" 175 | ;; 176 | help2man*) 177 | echo "You should only need it if you modified a dependency" \ 178 | "of a man page." 179 | echo "You may want to install the GNU Help2man package:" 180 | echo "<$gnu_software_URL/help2man/>" 181 | ;; 182 | makeinfo*) 183 | echo "You should only need it if you modified a '.texi' file, or" 184 | echo "any other file indirectly affecting the aspect of the manual." 185 | echo "You might want to install the Texinfo package:" 186 | echo "<$gnu_software_URL/texinfo/>" 187 | echo "The spurious makeinfo call might also be the consequence of" 188 | echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" 189 | echo "want to install GNU make:" 190 | echo "<$gnu_software_URL/make/>" 191 | ;; 192 | *) 193 | echo "You might have modified some files without having the proper" 194 | echo "tools for further handling them. Check the 'README' file, it" 195 | echo "often tells you about the needed prerequisites for installing" 196 | echo "this package. You may also peek at any GNU archive site, in" 197 | echo "case some other package contains this missing '$1' program." 198 | ;; 199 | esac 200 | } 201 | 202 | give_advice "$1" | sed -e '1s/^/WARNING: /' \ 203 | -e '2,$s/^/ /' >&2 204 | 205 | # Propagate the correct exit status (expected to be 127 for a program 206 | # not found, 63 for a program that failed due to version mismatch). 207 | exit $st 208 | 209 | # Local variables: 210 | # eval: (add-hook 'write-file-hooks 'time-stamp) 211 | # time-stamp-start: "scriptversion=" 212 | # time-stamp-format: "%:y-%02m-%02d.%02H" 213 | # time-stamp-time-zone: "UTC" 214 | # time-stamp-end: "; # UTC" 215 | # End: 216 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.69]) 5 | AC_INIT([GNU Superoptimizer Toolkit], [0.1], [james.pallister@embecosm.com]) 6 | AC_CONFIG_MACRO_DIR([m4]) 7 | AC_CONFIG_AUX_DIR([build-aux]) 8 | # AC_CONFIG_SRCDIR([src/]) 9 | AM_INIT_AUTOMAKE([subdir-objects foreign]) 10 | AM_MAINTAINER_MODE([disable]) 11 | 12 | : ${CXXFLAGS="-g"} 13 | 14 | # Checks for programs. 15 | AC_PROG_CXX 16 | AC_PROG_CC 17 | AC_PROG_MAKE_SET 18 | 19 | AX_CXX_COMPILE_STDCXX_11 20 | 21 | AX_MPI([HAVE_MPI=1]) 22 | if test -z "$HAVE_MPI"; then 23 | AC_MSG_WARN([Cannot build parallel superoptimizer: cannot find MPI]) 24 | fi 25 | AM_CONDITIONAL([HAVE_MPI], test -n "$HAVE_MPI") 26 | 27 | # Checks for libraries. 28 | # FIXME: Replace `main' with a function in `-lboost_unit_test_framework': 29 | AC_CHECK_LIB([boost_unit_test_framework], [main]) 30 | 31 | # Checks for header files. 32 | AC_CHECK_HEADERS([stdint.h string.h]) 33 | 34 | # Checks for typedefs, structures, and compiler characteristics. 35 | AC_CHECK_HEADER_STDBOOL 36 | AC_C_INLINE 37 | AC_TYPE_SIZE_T 38 | AC_TYPE_UINT16_T 39 | AC_TYPE_UINT32_T 40 | AC_TYPE_UINT64_T 41 | AC_TYPE_UINT8_T 42 | AC_CHECK_TYPES([ptrdiff_t]) 43 | 44 | # Checks for library functions. 45 | AC_FUNC_STRERROR_R 46 | AC_CHECK_FUNCS([strerror]) 47 | 48 | # Documentation 49 | 50 | # The doxygen-config.in expands the macro @SRCDIR@ so that doxygen can be run 51 | # in the build directory, when doing an out of tree build 52 | mkdir -p doc/doxygen 53 | DX_INIT_DOXYGEN("GNU Superoptimizer Toolkit", doc/doxygen-config, [doc/doxygen]) 54 | DX_DOXYGEN_FEATURE(ON) 55 | DX_PDF_FEATURE(ON) 56 | DX_HTML_FEATURE(ON) 57 | 58 | AC_CHECK_PROG(PDFLATEX, pdflatex, pdflatex) 59 | if test -z "$PDFLATEX"; then 60 | AC_MSG_WARN([Cannot build design document: require pdflatex]) 61 | fi 62 | AM_CONDITIONAL([HAVE_PDFLATEX], test -n "$PDFLATEX") 63 | 64 | # Link in test files 65 | AC_CONFIG_LINKS([ 66 | tests/data/long_1.csv:tests/data/long_1.csv 67 | tests/data/long_2.csv:tests/data/long_2.csv 68 | tests/data/sparse_4.csv:tests/data/sparse_4.csv 69 | tests/data/sparse_5.csv:tests/data/sparse_5.csv 70 | tests/data/standard_1.csv:tests/data/standard_1.csv 71 | tests/data/standard_2.csv:tests/data/standard_2.csv 72 | ]) 73 | 74 | AC_CONFIG_FILES([Makefile doxygen.mk doc/doxygen-config]) 75 | AC_OUTPUT 76 | -------------------------------------------------------------------------------- /doc/doxygen-config.in: -------------------------------------------------------------------------------- 1 | # Doxyfile 1.8.9.1 2 | 3 | #--------------------------------------------------------------------------- 4 | # Project related configuration options 5 | #--------------------------------------------------------------------------- 6 | DOXYFILE_ENCODING = UTF-8 7 | PROJECT_NAME = @PACKAGE_NAME@ 8 | PROJECT_NUMBER = @PACKAGE_VERSION@ 9 | PROJECT_BRIEF = 10 | PROJECT_LOGO = 11 | OUTPUT_DIRECTORY = doc/doxygen 12 | CREATE_SUBDIRS = NO 13 | ALLOW_UNICODE_NAMES = NO 14 | OUTPUT_LANGUAGE = English 15 | BRIEF_MEMBER_DESC = YES 16 | REPEAT_BRIEF = YES 17 | ABBREVIATE_BRIEF = "The $name class" \ 18 | "The $name widget" \ 19 | "The $name file" \ 20 | is \ 21 | provides \ 22 | specifies \ 23 | contains \ 24 | represents \ 25 | a \ 26 | an \ 27 | the 28 | ALWAYS_DETAILED_SEC = NO 29 | INLINE_INHERITED_MEMB = NO 30 | FULL_PATH_NAMES = YES 31 | STRIP_FROM_PATH = 32 | STRIP_FROM_INC_PATH = 33 | SHORT_NAMES = NO 34 | JAVADOC_AUTOBRIEF = NO 35 | QT_AUTOBRIEF = NO 36 | MULTILINE_CPP_IS_BRIEF = NO 37 | INHERIT_DOCS = YES 38 | SEPARATE_MEMBER_PAGES = NO 39 | TAB_SIZE = 4 40 | ALIASES = 41 | TCL_SUBST = 42 | OPTIMIZE_OUTPUT_FOR_C = NO 43 | OPTIMIZE_OUTPUT_JAVA = NO 44 | OPTIMIZE_FOR_FORTRAN = NO 45 | OPTIMIZE_OUTPUT_VHDL = NO 46 | EXTENSION_MAPPING = 47 | MARKDOWN_SUPPORT = YES 48 | AUTOLINK_SUPPORT = YES 49 | BUILTIN_STL_SUPPORT = NO 50 | CPP_CLI_SUPPORT = NO 51 | SIP_SUPPORT = NO 52 | IDL_PROPERTY_SUPPORT = YES 53 | DISTRIBUTE_GROUP_DOC = NO 54 | SUBGROUPING = YES 55 | INLINE_GROUPED_CLASSES = NO 56 | INLINE_SIMPLE_STRUCTS = NO 57 | TYPEDEF_HIDES_STRUCT = NO 58 | LOOKUP_CACHE_SIZE = 0 59 | #--------------------------------------------------------------------------- 60 | # Build related configuration options 61 | #--------------------------------------------------------------------------- 62 | EXTRACT_ALL = YES 63 | EXTRACT_PRIVATE = NO 64 | EXTRACT_PACKAGE = NO 65 | EXTRACT_STATIC = NO 66 | EXTRACT_LOCAL_CLASSES = YES 67 | EXTRACT_LOCAL_METHODS = NO 68 | EXTRACT_ANON_NSPACES = NO 69 | HIDE_UNDOC_MEMBERS = NO 70 | HIDE_UNDOC_CLASSES = NO 71 | HIDE_FRIEND_COMPOUNDS = NO 72 | HIDE_IN_BODY_DOCS = NO 73 | INTERNAL_DOCS = NO 74 | CASE_SENSE_NAMES = NO 75 | HIDE_SCOPE_NAMES = NO 76 | HIDE_COMPOUND_REFERENCE= NO 77 | SHOW_INCLUDE_FILES = YES 78 | SHOW_GROUPED_MEMB_INC = NO 79 | FORCE_LOCAL_INCLUDES = NO 80 | INLINE_INFO = YES 81 | SORT_MEMBER_DOCS = YES 82 | SORT_BRIEF_DOCS = NO 83 | SORT_MEMBERS_CTORS_1ST = NO 84 | SORT_GROUP_NAMES = NO 85 | SORT_BY_SCOPE_NAME = NO 86 | STRICT_PROTO_MATCHING = NO 87 | GENERATE_TODOLIST = YES 88 | GENERATE_TESTLIST = YES 89 | GENERATE_BUGLIST = YES 90 | GENERATE_DEPRECATEDLIST= YES 91 | ENABLED_SECTIONS = 92 | MAX_INITIALIZER_LINES = 30 93 | SHOW_USED_FILES = YES 94 | SHOW_FILES = YES 95 | SHOW_NAMESPACES = YES 96 | FILE_VERSION_FILTER = 97 | LAYOUT_FILE = 98 | CITE_BIB_FILES = 99 | #--------------------------------------------------------------------------- 100 | # Configuration options related to warning and progress messages 101 | #--------------------------------------------------------------------------- 102 | QUIET = NO 103 | WARNINGS = YES 104 | WARN_IF_UNDOCUMENTED = YES 105 | WARN_IF_DOC_ERROR = YES 106 | WARN_NO_PARAMDOC = NO 107 | WARN_FORMAT = "$file:$line: $text" 108 | WARN_LOGFILE = 109 | #--------------------------------------------------------------------------- 110 | # Configuration options related to the input files 111 | #--------------------------------------------------------------------------- 112 | INPUT = @abs_top_srcdir@/src 113 | INPUT_ENCODING = UTF-8 114 | FILE_PATTERNS = *.c \ 115 | *.cc \ 116 | *.cxx \ 117 | *.cpp \ 118 | *.c++ \ 119 | *.java \ 120 | *.ii \ 121 | *.ixx \ 122 | *.ipp \ 123 | *.i++ \ 124 | *.inl \ 125 | *.idl \ 126 | *.ddl \ 127 | *.odl \ 128 | *.h \ 129 | *.hh \ 130 | *.hxx \ 131 | *.hpp \ 132 | *.h++ \ 133 | *.cs \ 134 | *.d \ 135 | *.php \ 136 | *.php4 \ 137 | *.php5 \ 138 | *.phtml \ 139 | *.inc \ 140 | *.m \ 141 | *.markdown \ 142 | *.md \ 143 | *.mm \ 144 | *.dox \ 145 | *.py \ 146 | *.f90 \ 147 | *.f \ 148 | *.for \ 149 | *.tcl \ 150 | *.vhd \ 151 | *.vhdl \ 152 | *.ucf \ 153 | *.qsf \ 154 | *.as \ 155 | *.js 156 | RECURSIVE = YES 157 | EXCLUDE = 158 | EXCLUDE_SYMLINKS = NO 159 | EXCLUDE_PATTERNS = *_gen.hpp 160 | EXCLUDE_SYMBOLS = 161 | EXAMPLE_PATH = 162 | EXAMPLE_PATTERNS = * 163 | EXAMPLE_RECURSIVE = NO 164 | IMAGE_PATH = 165 | INPUT_FILTER = 166 | FILTER_PATTERNS = 167 | FILTER_SOURCE_FILES = NO 168 | FILTER_SOURCE_PATTERNS = 169 | USE_MDFILE_AS_MAINPAGE = 170 | #--------------------------------------------------------------------------- 171 | # Configuration options related to source browsing 172 | #--------------------------------------------------------------------------- 173 | SOURCE_BROWSER = NO 174 | INLINE_SOURCES = NO 175 | STRIP_CODE_COMMENTS = YES 176 | REFERENCED_BY_RELATION = NO 177 | REFERENCES_RELATION = NO 178 | REFERENCES_LINK_SOURCE = YES 179 | SOURCE_TOOLTIPS = YES 180 | USE_HTAGS = NO 181 | VERBATIM_HEADERS = YES 182 | CLANG_ASSISTED_PARSING = NO 183 | CLANG_OPTIONS = 184 | #--------------------------------------------------------------------------- 185 | # Configuration options related to the alphabetical class index 186 | #--------------------------------------------------------------------------- 187 | ALPHABETICAL_INDEX = YES 188 | COLS_IN_ALPHA_INDEX = 5 189 | IGNORE_PREFIX = 190 | #--------------------------------------------------------------------------- 191 | # Configuration options related to the HTML output 192 | #--------------------------------------------------------------------------- 193 | GENERATE_HTML = YES 194 | HTML_OUTPUT = html 195 | HTML_FILE_EXTENSION = .html 196 | HTML_HEADER = 197 | HTML_FOOTER = 198 | HTML_STYLESHEET = 199 | HTML_EXTRA_STYLESHEET = 200 | HTML_EXTRA_FILES = 201 | HTML_COLORSTYLE_HUE = 220 202 | HTML_COLORSTYLE_SAT = 100 203 | HTML_COLORSTYLE_GAMMA = 80 204 | HTML_TIMESTAMP = YES 205 | HTML_DYNAMIC_SECTIONS = NO 206 | HTML_INDEX_NUM_ENTRIES = 100 207 | GENERATE_DOCSET = NO 208 | DOCSET_FEEDNAME = "Doxygen generated docs" 209 | DOCSET_BUNDLE_ID = org.doxygen.Project 210 | DOCSET_PUBLISHER_ID = org.doxygen.Publisher 211 | DOCSET_PUBLISHER_NAME = Publisher 212 | GENERATE_HTMLHELP = NO 213 | CHM_FILE = 214 | HHC_LOCATION = 215 | GENERATE_CHI = NO 216 | CHM_INDEX_ENCODING = 217 | BINARY_TOC = NO 218 | TOC_EXPAND = NO 219 | GENERATE_QHP = NO 220 | QCH_FILE = 221 | QHP_NAMESPACE = org.doxygen.Project 222 | QHP_VIRTUAL_FOLDER = doc 223 | QHP_CUST_FILTER_NAME = 224 | QHP_CUST_FILTER_ATTRS = 225 | QHP_SECT_FILTER_ATTRS = 226 | QHG_LOCATION = 227 | GENERATE_ECLIPSEHELP = NO 228 | ECLIPSE_DOC_ID = org.doxygen.Project 229 | DISABLE_INDEX = NO 230 | GENERATE_TREEVIEW = NO 231 | ENUM_VALUES_PER_LINE = 4 232 | TREEVIEW_WIDTH = 250 233 | EXT_LINKS_IN_WINDOW = NO 234 | FORMULA_FONTSIZE = 10 235 | FORMULA_TRANSPARENT = YES 236 | USE_MATHJAX = NO 237 | MATHJAX_FORMAT = HTML-CSS 238 | MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest 239 | MATHJAX_EXTENSIONS = 240 | MATHJAX_CODEFILE = 241 | SEARCHENGINE = YES 242 | SERVER_BASED_SEARCH = NO 243 | EXTERNAL_SEARCH = NO 244 | SEARCHENGINE_URL = 245 | SEARCHDATA_FILE = searchdata.xml 246 | EXTERNAL_SEARCH_ID = 247 | EXTRA_SEARCH_MAPPINGS = 248 | #--------------------------------------------------------------------------- 249 | # Configuration options related to the LaTeX output 250 | #--------------------------------------------------------------------------- 251 | GENERATE_LATEX = YES 252 | LATEX_OUTPUT = latex 253 | LATEX_CMD_NAME = latex 254 | MAKEINDEX_CMD_NAME = makeindex 255 | COMPACT_LATEX = NO 256 | PAPER_TYPE = a4 257 | EXTRA_PACKAGES = 258 | LATEX_HEADER = 259 | LATEX_FOOTER = 260 | LATEX_EXTRA_STYLESHEET = 261 | LATEX_EXTRA_FILES = 262 | PDF_HYPERLINKS = YES 263 | USE_PDFLATEX = YES 264 | LATEX_BATCHMODE = NO 265 | LATEX_HIDE_INDICES = NO 266 | LATEX_SOURCE_CODE = NO 267 | LATEX_BIB_STYLE = plain 268 | #--------------------------------------------------------------------------- 269 | # Configuration options related to the RTF output 270 | #--------------------------------------------------------------------------- 271 | GENERATE_RTF = NO 272 | RTF_OUTPUT = rtf 273 | COMPACT_RTF = NO 274 | RTF_HYPERLINKS = NO 275 | RTF_STYLESHEET_FILE = 276 | RTF_EXTENSIONS_FILE = 277 | RTF_SOURCE_CODE = NO 278 | #--------------------------------------------------------------------------- 279 | # Configuration options related to the man page output 280 | #--------------------------------------------------------------------------- 281 | GENERATE_MAN = NO 282 | MAN_OUTPUT = man 283 | MAN_EXTENSION = .3 284 | MAN_SUBDIR = 285 | MAN_LINKS = NO 286 | #--------------------------------------------------------------------------- 287 | # Configuration options related to the XML output 288 | #--------------------------------------------------------------------------- 289 | GENERATE_XML = NO 290 | XML_OUTPUT = xml 291 | XML_PROGRAMLISTING = YES 292 | #--------------------------------------------------------------------------- 293 | # Configuration options related to the DOCBOOK output 294 | #--------------------------------------------------------------------------- 295 | GENERATE_DOCBOOK = NO 296 | DOCBOOK_OUTPUT = docbook 297 | DOCBOOK_PROGRAMLISTING = NO 298 | #--------------------------------------------------------------------------- 299 | # Configuration options for the AutoGen Definitions output 300 | #--------------------------------------------------------------------------- 301 | GENERATE_AUTOGEN_DEF = NO 302 | #--------------------------------------------------------------------------- 303 | # Configuration options related to the Perl module output 304 | #--------------------------------------------------------------------------- 305 | GENERATE_PERLMOD = NO 306 | PERLMOD_LATEX = NO 307 | PERLMOD_PRETTY = YES 308 | PERLMOD_MAKEVAR_PREFIX = 309 | #--------------------------------------------------------------------------- 310 | # Configuration options related to the preprocessor 311 | #--------------------------------------------------------------------------- 312 | ENABLE_PREPROCESSING = YES 313 | MACRO_EXPANSION = NO 314 | EXPAND_ONLY_PREDEF = NO 315 | SEARCH_INCLUDES = YES 316 | INCLUDE_PATH = 317 | INCLUDE_FILE_PATTERNS = 318 | PREDEFINED = 319 | EXPAND_AS_DEFINED = 320 | SKIP_FUNCTION_MACROS = YES 321 | #--------------------------------------------------------------------------- 322 | # Configuration options related to external references 323 | #--------------------------------------------------------------------------- 324 | TAGFILES = 325 | GENERATE_TAGFILE = 326 | ALLEXTERNALS = NO 327 | EXTERNAL_GROUPS = YES 328 | EXTERNAL_PAGES = YES 329 | PERL_PATH = /usr/bin/perl 330 | #--------------------------------------------------------------------------- 331 | # Configuration options related to the dot tool 332 | #--------------------------------------------------------------------------- 333 | CLASS_DIAGRAMS = YES 334 | MSCGEN_PATH = 335 | DIA_PATH = 336 | HIDE_UNDOC_RELATIONS = YES 337 | HAVE_DOT = YES 338 | DOT_NUM_THREADS = 0 339 | DOT_FONTNAME = Helvetica 340 | DOT_FONTSIZE = 10 341 | DOT_FONTPATH = 342 | CLASS_GRAPH = YES 343 | COLLABORATION_GRAPH = YES 344 | GROUP_GRAPHS = YES 345 | UML_LOOK = NO 346 | UML_LIMIT_NUM_FIELDS = 10 347 | TEMPLATE_RELATIONS = NO 348 | INCLUDE_GRAPH = YES 349 | INCLUDED_BY_GRAPH = YES 350 | CALL_GRAPH = NO 351 | CALLER_GRAPH = NO 352 | GRAPHICAL_HIERARCHY = YES 353 | DIRECTORY_GRAPH = YES 354 | DOT_IMAGE_FORMAT = png 355 | INTERACTIVE_SVG = NO 356 | DOT_PATH = 357 | DOTFILE_DIRS = 358 | MSCFILE_DIRS = 359 | DIAFILE_DIRS = 360 | PLANTUML_JAR_PATH = 361 | PLANTUML_INCLUDE_PATH = 362 | DOT_GRAPH_MAX_NODES = 50 363 | MAX_DOT_GRAPH_DEPTH = 0 364 | DOT_TRANSPARENT = NO 365 | DOT_MULTI_TARGETS = NO 366 | GENERATE_LEGEND = YES 367 | DOT_CLEANUP = YES 368 | -------------------------------------------------------------------------------- /doc/uops.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \title{$GSO^2$: GNU SuperOptimizer Omega. \\ \emph{ $\mu$ops design}} 4 | \author{James Pallister} 5 | 6 | \begin{document} 7 | 8 | \maketitle 9 | \newcommand{\uop}{$\mu$op} 10 | \newcommand{\uops}{$\mu$ops} 11 | 12 | \section{Introduction} 13 | 14 | $GSO^2$ describes all of the target processor's instruction in $\mu$ops. These \uops follow a small three operand instruction set, and can be easily translated into code that will run on the host processor (the processor performing the superoptimizer). 15 | 16 | \section{The \uops} 17 | 18 | TODO 19 | 20 | \end{document} 21 | -------------------------------------------------------------------------------- /doxygen.mk.am: -------------------------------------------------------------------------------- 1 | 2 | ## --------------------------------- ## 3 | ## Format-independent Doxygen rules. ## 4 | ## --------------------------------- ## 5 | 6 | if DX_COND_doc 7 | 8 | ## ------------------------------- ## 9 | ## Rules specific for HTML output. ## 10 | ## ------------------------------- ## 11 | 12 | if DX_COND_html 13 | 14 | DX_CLEAN_HTML = @DX_DOCDIR@/html 15 | 16 | endif DX_COND_html 17 | 18 | ## ------------------------------ ## 19 | ## Rules specific for CHM output. ## 20 | ## ------------------------------ ## 21 | 22 | if DX_COND_chm 23 | 24 | DX_CLEAN_CHM = @DX_DOCDIR@/chm 25 | 26 | if DX_COND_chi 27 | 28 | DX_CLEAN_CHI = @DX_DOCDIR@/@PACKAGE@.chi 29 | 30 | endif DX_COND_chi 31 | 32 | endif DX_COND_chm 33 | 34 | ## ------------------------------ ## 35 | ## Rules specific for MAN output. ## 36 | ## ------------------------------ ## 37 | 38 | if DX_COND_man 39 | 40 | DX_CLEAN_MAN = @DX_DOCDIR@/man 41 | 42 | endif DX_COND_man 43 | 44 | ## ------------------------------ ## 45 | ## Rules specific for RTF output. ## 46 | ## ------------------------------ ## 47 | 48 | if DX_COND_rtf 49 | 50 | DX_CLEAN_RTF = @DX_DOCDIR@/rtf 51 | 52 | endif DX_COND_rtf 53 | 54 | ## ------------------------------ ## 55 | ## Rules specific for XML output. ## 56 | ## ------------------------------ ## 57 | 58 | if DX_COND_xml 59 | 60 | DX_CLEAN_XML = @DX_DOCDIR@/xml 61 | 62 | endif DX_COND_xml 63 | 64 | ## ----------------------------- ## 65 | ## Rules specific for PS output. ## 66 | ## ----------------------------- ## 67 | 68 | if DX_COND_ps 69 | 70 | DX_CLEAN_PS = @DX_DOCDIR@/@PACKAGE@.ps 71 | 72 | DX_PS_GOAL = doxygen-ps 73 | 74 | doxygen-ps: @DX_DOCDIR@/@PACKAGE@.ps 75 | 76 | @DX_DOCDIR@/@PACKAGE@.ps: @DX_DOCDIR@/@PACKAGE@.tag 77 | cd @DX_DOCDIR@/latex; \ 78 | rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \ 79 | $(DX_LATEX) refman.tex; \ 80 | $(MAKEINDEX_PATH) refman.idx; \ 81 | $(DX_LATEX) refman.tex; \ 82 | countdown=5; \ 83 | while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \ 84 | refman.log > /dev/null 2>&1 \ 85 | && test $$countdown -gt 0; do \ 86 | $(DX_LATEX) refman.tex; \ 87 | countdown=`expr $$countdown - 1`; \ 88 | done; \ 89 | $(DX_DVIPS) -o ../@PACKAGE@.ps refman.dvi 90 | 91 | endif DX_COND_ps 92 | 93 | ## ------------------------------ ## 94 | ## Rules specific for PDF output. ## 95 | ## ------------------------------ ## 96 | 97 | if DX_COND_pdf 98 | 99 | DX_CLEAN_PDF = @DX_DOCDIR@/@PACKAGE@.pdf 100 | 101 | DX_PDF_GOAL = doxygen-pdf 102 | 103 | doxygen-pdf: @DX_DOCDIR@/@PACKAGE@.pdf 104 | 105 | @DX_DOCDIR@/@PACKAGE@.pdf: @DX_DOCDIR@/@PACKAGE@.tag 106 | cd @DX_DOCDIR@/latex; \ 107 | rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \ 108 | $(DX_PDFLATEX) refman.tex; \ 109 | $(DX_MAKEINDEX) refman.idx; \ 110 | $(DX_PDFLATEX) refman.tex; \ 111 | countdown=5; \ 112 | while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \ 113 | refman.log > /dev/null 2>&1 \ 114 | && test $$countdown -gt 0; do \ 115 | $(DX_PDFLATEX) refman.tex; \ 116 | countdown=`expr $$countdown - 1`; \ 117 | done; \ 118 | mv refman.pdf ../@PACKAGE@.pdf 119 | 120 | endif DX_COND_pdf 121 | 122 | ## ------------------------------------------------- ## 123 | ## Rules specific for LaTeX (shared for PS and PDF). ## 124 | ## ------------------------------------------------- ## 125 | 126 | if DX_COND_latex 127 | 128 | DX_CLEAN_LATEX = @DX_DOCDIR@/latex 129 | 130 | endif DX_COND_latex 131 | 132 | .PHONY: doxygen-run doxygen-doc $(DX_PS_GOAL) $(DX_PDF_GOAL) 133 | 134 | .INTERMEDIATE: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL) 135 | 136 | doxygen-run: @DX_DOCDIR@/@PACKAGE@.tag 137 | 138 | doxygen-doc: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL) 139 | 140 | # Slight modification from default provided configuration to support out of 141 | # tree builds 142 | @DX_DOCDIR@/@PACKAGE@.tag: $(DX_CONFIG) $(pkginclude_HEADERS) 143 | rm -rf @DX_DOCDIR@ 144 | $(DX_ENV) $(DX_DOXYGEN) $(DX_CONFIG) 145 | echo Timestamp >$@ 146 | 147 | DX_CLEANFILES = \ 148 | @DX_DOCDIR@/@PACKAGE@.tag \ 149 | -r \ 150 | $(DX_CLEAN_HTML) \ 151 | $(DX_CLEAN_CHM) \ 152 | $(DX_CLEAN_CHI) \ 153 | $(DX_CLEAN_MAN) \ 154 | $(DX_CLEAN_RTF) \ 155 | $(DX_CLEAN_XML) \ 156 | $(DX_CLEAN_PS) \ 157 | $(DX_CLEAN_PDF) \ 158 | $(DX_CLEAN_LATEX) 159 | 160 | endif DX_COND_doc 161 | 162 | # 163 | # LICENSE 164 | # 165 | # Copyright (c) 2009 Oren Ben-Kiki 166 | # 167 | # Copying and distribution of this file, with or without modification, are 168 | # permitted in any medium without royalty provided the copyright notice 169 | # and this notice are preserved. This file is offered as-is, without any 170 | # warranty. 171 | -------------------------------------------------------------------------------- /libraries/cppinput/cppinput.hpp: -------------------------------------------------------------------------------- 1 | // CPPInput library header file 2 | // Copyright (c) James Pallister, All rights reserved. 3 | 4 | // This library is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU Lesser General Public 6 | // License as published by the Free Software Foundation; either 7 | // version 3.0 of the License, or (at your option) any later version. 8 | 9 | // This library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | // Lesser General Public License for more details. 13 | 14 | // You should have received a copy of the GNU Lesser General Public 15 | // License along with this library. 16 | 17 | #ifndef __CPPINPUT_HPP__ 18 | #define __CPPINPUT_HPP__ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | namespace cppinput 27 | { 28 | 29 | namespace ci_private 30 | { 31 | // Split the format string into a test string before the specifier, the 32 | // specifier, and the remainder of the string. 33 | inline bool nextSpecifier(std::string fmt, std::string &pre_match, 34 | std::string &specifier, std::string &post_match) 35 | { 36 | unsigned i = 0, j = 0; 37 | 38 | bool found_start = false; 39 | bool found_end = false; 40 | 41 | for(; i < fmt.size(); ++i) 42 | { 43 | if(fmt[i] == '{') 44 | { 45 | if(i < fmt.size()-1) 46 | { 47 | if(fmt[i+1] != '{') 48 | { 49 | found_start = true; 50 | break; 51 | } 52 | } 53 | else 54 | { 55 | // TODO: raise proper exception 56 | assert(!"Invalid format string. TODO - raise proper exception"); 57 | } 58 | } 59 | } 60 | 61 | if(!found_start) 62 | { 63 | pre_match = fmt; 64 | return false; 65 | } 66 | 67 | pre_match = fmt.substr(0, i); 68 | 69 | for(j = i; j < fmt.size(); ++j) 70 | { 71 | if(fmt[j] == '}') 72 | { 73 | found_end = true; 74 | break; 75 | } 76 | } 77 | 78 | if(!found_end) 79 | { 80 | // TODO: raise proper exception 81 | assert(!"Invalid format string. TODO - raise proper exception"); 82 | } 83 | 84 | specifier = fmt.substr(i, j-i+1); 85 | post_match = fmt.substr(j+1); 86 | 87 | return true; 88 | } 89 | }; // namespace private 90 | 91 | inline bool input(std::istream &in, std::string fmt) 92 | { 93 | std::string pre_match, specifier, post_match; 94 | bool have_specifier = ci_private::nextSpecifier(fmt, pre_match, specifier, post_match); 95 | 96 | if(have_specifier) 97 | { 98 | // Error, we have no types left! 99 | return false; 100 | } 101 | 102 | for(unsigned i = 0; i < fmt.size(); ++i) 103 | { 104 | char c; 105 | 106 | in.get(c); 107 | if(c != fmt[i]) 108 | { 109 | in.setstate(std::ios::failbit); 110 | return false; 111 | } 112 | } 113 | 114 | return true; 115 | } 116 | 117 | // Input from the given stream, as specified by the format string fmt, storing 118 | // the values in the params provided. 119 | template 120 | bool input(std::istream &in, std::string fmt, V &value, Values &... params) 121 | { 122 | std::string pre_match, specifier, post_match; 123 | bool have_specifier; 124 | 125 | have_specifier = ci_private::nextSpecifier(fmt, pre_match, specifier, post_match); 126 | 127 | // First, match prematch 128 | for(unsigned i = 0; i < pre_match.size(); ++i) 129 | { 130 | char c; 131 | 132 | // in >> c; 133 | in.get(c); 134 | if(c != pre_match[i]) 135 | { 136 | in.setstate(std::ios::failbit); 137 | return false; 138 | } 139 | } 140 | 141 | if(have_specifier) 142 | { 143 | // Then, input as per the specifier 144 | in >> value; 145 | 146 | // Finally, recurse with the rest of the string 147 | return input(in, post_match, params...); 148 | } 149 | 150 | return true; 151 | } 152 | 153 | template 154 | bool input(std::istream &in, std::string fmt) 155 | { 156 | // Just match fmt 157 | for(unsigned i = 0; i < fmt.size(); ++i) 158 | { 159 | char c; 160 | 161 | in.get(c); 162 | if(c != fmt[i]) 163 | { 164 | in.setstate(std::ios::failbit); 165 | return false; 166 | } 167 | } 168 | } 169 | 170 | template 171 | bool input(std::string &in, std::string fmt, Values &... params) 172 | { 173 | std::stringstream ss(in); 174 | return input(ss, fmt, params...); 175 | } 176 | 177 | 178 | }; // namespace cppinput 179 | 180 | #endif 181 | -------------------------------------------------------------------------------- /m4/ax_cxx_compile_stdcxx_11.m4: -------------------------------------------------------------------------------- 1 | # ============================================================================ 2 | # http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html 3 | # ============================================================================ 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check for baseline language coverage in the compiler for the C++11 12 | # standard; if necessary, add switches to CXXFLAGS to enable support. 13 | # 14 | # The first argument, if specified, indicates whether you insist on an 15 | # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. 16 | # -std=c++11). If neither is specified, you get whatever works, with 17 | # preference for an extended mode. 18 | # 19 | # The second argument, if specified 'mandatory' or if left unspecified, 20 | # indicates that baseline C++11 support is required and that the macro 21 | # should error out if no mode with that support is found. If specified 22 | # 'optional', then configuration proceeds regardless, after defining 23 | # HAVE_CXX11 if and only if a supporting mode is found. 24 | # 25 | # LICENSE 26 | # 27 | # Copyright (c) 2008 Benjamin Kosnik 28 | # Copyright (c) 2012 Zack Weinberg 29 | # Copyright (c) 2013 Roy Stogner 30 | # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov 31 | # Copyright (c) 2015 Paul Norman 32 | # 33 | # Copying and distribution of this file, with or without modification, are 34 | # permitted in any medium without royalty provided the copyright notice 35 | # and this notice are preserved. This file is offered as-is, without any 36 | # warranty. 37 | 38 | #serial 12 39 | 40 | m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[ 41 | template 42 | struct check 43 | { 44 | static_assert(sizeof(int) <= sizeof(T), "not big enough"); 45 | }; 46 | 47 | struct Base { 48 | virtual void f() {} 49 | }; 50 | struct Child : public Base { 51 | virtual void f() override {} 52 | }; 53 | 54 | typedef check> right_angle_brackets; 55 | 56 | int a; 57 | decltype(a) b; 58 | 59 | typedef check check_type; 60 | check_type c; 61 | check_type&& cr = static_cast(c); 62 | 63 | auto d = a; 64 | auto l = [](){}; 65 | // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable] 66 | struct use_l { use_l() { l(); } }; 67 | 68 | // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae 69 | // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this 70 | namespace test_template_alias_sfinae { 71 | struct foo {}; 72 | 73 | template 74 | using member = typename T::member_type; 75 | 76 | template 77 | void func(...) {} 78 | 79 | template 80 | void func(member*) {} 81 | 82 | void test(); 83 | 84 | void test() { 85 | func(0); 86 | } 87 | } 88 | 89 | // Check for C++11 attribute support 90 | void noret [[noreturn]] () { throw 0; } 91 | ]]) 92 | 93 | AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl 94 | m4_if([$1], [], [], 95 | [$1], [ext], [], 96 | [$1], [noext], [], 97 | [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl 98 | m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], 99 | [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], 100 | [$2], [optional], [ax_cxx_compile_cxx11_required=false], 101 | [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])]) 102 | AC_LANG_PUSH([C++])dnl 103 | ac_success=no 104 | AC_CACHE_CHECK(whether $CXX supports C++11 features by default, 105 | ax_cv_cxx_compile_cxx11, 106 | [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], 107 | [ax_cv_cxx_compile_cxx11=yes], 108 | [ax_cv_cxx_compile_cxx11=no])]) 109 | if test x$ax_cv_cxx_compile_cxx11 = xyes; then 110 | ac_success=yes 111 | fi 112 | 113 | m4_if([$1], [noext], [], [dnl 114 | if test x$ac_success = xno; then 115 | for switch in -std=gnu++11 -std=gnu++0x; do 116 | cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) 117 | AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, 118 | $cachevar, 119 | [ac_save_CXXFLAGS="$CXXFLAGS" 120 | CXXFLAGS="$CXXFLAGS $switch" 121 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], 122 | [eval $cachevar=yes], 123 | [eval $cachevar=no]) 124 | CXXFLAGS="$ac_save_CXXFLAGS"]) 125 | if eval test x\$$cachevar = xyes; then 126 | CXXFLAGS="$CXXFLAGS $switch" 127 | ac_success=yes 128 | break 129 | fi 130 | done 131 | fi]) 132 | 133 | m4_if([$1], [ext], [], [dnl 134 | if test x$ac_success = xno; then 135 | dnl HP's aCC needs +std=c++11 according to: 136 | dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf 137 | for switch in -std=c++11 -std=c++0x +std=c++11; do 138 | cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) 139 | AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, 140 | $cachevar, 141 | [ac_save_CXXFLAGS="$CXXFLAGS" 142 | CXXFLAGS="$CXXFLAGS $switch" 143 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], 144 | [eval $cachevar=yes], 145 | [eval $cachevar=no]) 146 | CXXFLAGS="$ac_save_CXXFLAGS"]) 147 | if eval test x\$$cachevar = xyes; then 148 | CXXFLAGS="$CXXFLAGS $switch" 149 | ac_success=yes 150 | break 151 | fi 152 | done 153 | fi]) 154 | AC_LANG_POP([C++]) 155 | if test x$ax_cxx_compile_cxx11_required = xtrue; then 156 | if test x$ac_success = xno; then 157 | AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) 158 | fi 159 | else 160 | if test x$ac_success = xno; then 161 | HAVE_CXX11=0 162 | AC_MSG_NOTICE([No compiler with C++11 support was found]) 163 | else 164 | HAVE_CXX11=1 165 | AC_DEFINE(HAVE_CXX11,1, 166 | [define if the compiler supports basic C++11 syntax]) 167 | fi 168 | 169 | AC_SUBST(HAVE_CXX11) 170 | fi 171 | ]) 172 | -------------------------------------------------------------------------------- /m4/ax_mpi.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_mpi.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_MPI([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # This macro tries to find out how to compile programs that use MPI 12 | # (Message Passing Interface), a standard API for parallel process 13 | # communication (see http://www-unix.mcs.anl.gov/mpi/) 14 | # 15 | # On success, it sets the MPICC, MPICXX, MPIF77, or MPIFC output variable 16 | # to the name of the MPI compiler, depending upon the current language. 17 | # (This may just be $CC/$CXX/$F77/$FC, but is more often something like 18 | # mpicc/mpiCC/mpif77/mpif90.) It also sets MPILIBS to any libraries that 19 | # are needed for linking MPI (e.g. -lmpi or -lfmpi, if a special 20 | # MPICC/MPICXX/MPIF77/MPIFC was not found). 21 | # 22 | # Note that this macro should be used only if you just have a few source 23 | # files that need to be compiled using MPI. In particular, you should 24 | # neither overwrite CC/CXX/F77/FC with the values of 25 | # MPICC/MPICXX/MPIF77/MPIFC, nor assume that you can use the same flags 26 | # etc. as the standard compilers. If you want to compile a whole program 27 | # using the MPI compiler commands, use one of the macros 28 | # AX_PROG_{CC,CXX,FC}_MPI. 29 | # 30 | # ACTION-IF-FOUND is a list of shell commands to run if an MPI library is 31 | # found, and ACTION-IF-NOT-FOUND is a list of commands to run if it is not 32 | # found. If ACTION-IF-FOUND is not specified, the default action will 33 | # define HAVE_MPI. 34 | # 35 | # LICENSE 36 | # 37 | # Copyright (c) 2008 Steven G. Johnson 38 | # Copyright (c) 2008 Julian C. Cummings 39 | # 40 | # This program is free software: you can redistribute it and/or modify it 41 | # under the terms of the GNU General Public License as published by the 42 | # Free Software Foundation, either version 3 of the License, or (at your 43 | # option) any later version. 44 | # 45 | # This program is distributed in the hope that it will be useful, but 46 | # WITHOUT ANY WARRANTY; without even the implied warranty of 47 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 48 | # Public License for more details. 49 | # 50 | # You should have received a copy of the GNU General Public License along 51 | # with this program. If not, see . 52 | # 53 | # As a special exception, the respective Autoconf Macro's copyright owner 54 | # gives unlimited permission to copy, distribute and modify the configure 55 | # scripts that are the output of Autoconf when processing the Macro. You 56 | # need not follow the terms of the GNU General Public License when using 57 | # or distributing such scripts, even though portions of the text of the 58 | # Macro appear in them. The GNU General Public License (GPL) does govern 59 | # all other use of the material that constitutes the Autoconf Macro. 60 | # 61 | # This special exception to the GPL applies to versions of the Autoconf 62 | # Macro released by the Autoconf Archive. When you make and distribute a 63 | # modified version of the Autoconf Macro, you may extend this special 64 | # exception to the GPL to apply to your modified version as well. 65 | 66 | #serial 8 67 | 68 | AU_ALIAS([ACX_MPI], [AX_MPI]) 69 | AC_DEFUN([AX_MPI], [ 70 | AC_PREREQ(2.50) dnl for AC_LANG_CASE 71 | 72 | AC_REQUIRE([AC_PROG_CC]) 73 | AC_ARG_VAR(MPICC,[MPI C compiler command]) 74 | AC_CHECK_PROGS(MPICC, mpicc hcc mpxlc_r mpxlc mpcc cmpicc, $CC) 75 | ax_mpi_save_CC="$CC" 76 | CC="$MPICC" 77 | AC_SUBST(MPICC) 78 | 79 | AC_REQUIRE([AC_PROG_CXX]) 80 | AC_ARG_VAR(MPICXX,[MPI C++ compiler command]) 81 | AC_CHECK_PROGS(MPICXX, mpic++ mpicxx mpiCC hcp mpxlC_r mpxlC mpCC cmpic++, $CXX) 82 | ax_mpi_save_CXX="$CXX" 83 | CXX="$MPICXX" 84 | AC_SUBST(MPICXX) 85 | 86 | if test x = x"$MPILIBS"; then 87 | AC_LANG_CASE([C], [AC_CHECK_FUNC(MPI_Init, [MPILIBS=" "])], 88 | [C++], [AC_CHECK_FUNC(MPI_Init, [MPILIBS=" "])], 89 | [Fortran 77], [AC_MSG_CHECKING([for MPI_Init]) 90 | AC_LINK_IFELSE([AC_LANG_PROGRAM([],[ call MPI_Init])],[MPILIBS=" " 91 | AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)])], 92 | [Fortran], [AC_MSG_CHECKING([for MPI_Init]) 93 | AC_LINK_IFELSE([AC_LANG_PROGRAM([],[ call MPI_Init])],[MPILIBS=" " 94 | AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)])]) 95 | fi 96 | AC_LANG_CASE([Fortran 77], [ 97 | if test x = x"$MPILIBS"; then 98 | AC_CHECK_LIB(fmpi, MPI_Init, [MPILIBS="-lfmpi"]) 99 | fi 100 | if test x = x"$MPILIBS"; then 101 | AC_CHECK_LIB(fmpich, MPI_Init, [MPILIBS="-lfmpich"]) 102 | fi 103 | ], 104 | [Fortran], [ 105 | if test x = x"$MPILIBS"; then 106 | AC_CHECK_LIB(fmpi, MPI_Init, [MPILIBS="-lfmpi"]) 107 | fi 108 | if test x = x"$MPILIBS"; then 109 | AC_CHECK_LIB(mpichf90, MPI_Init, [MPILIBS="-lmpichf90"]) 110 | fi 111 | ]) 112 | if test x = x"$MPILIBS"; then 113 | AC_CHECK_LIB(mpi, MPI_Init, [MPILIBS="-lmpi"]) 114 | fi 115 | if test x = x"$MPILIBS"; then 116 | AC_CHECK_LIB(mpich, MPI_Init, [MPILIBS="-lmpich"]) 117 | fi 118 | 119 | dnl We have to use AC_TRY_COMPILE and not AC_CHECK_HEADER because the 120 | dnl latter uses $CPP, not $CC (which may be mpicc). 121 | AC_LANG_CASE([C], [if test x != x"$MPILIBS"; then 122 | AC_MSG_CHECKING([for mpi.h]) 123 | AC_TRY_COMPILE([#include ],[],[AC_MSG_RESULT(yes)], [MPILIBS="" 124 | AC_MSG_RESULT(no)]) 125 | fi], 126 | [C++], [if test x != x"$MPILIBS"; then 127 | AC_MSG_CHECKING([for mpi.h]) 128 | AC_TRY_COMPILE([#include ],[],[AC_MSG_RESULT(yes)], [MPILIBS="" 129 | AC_MSG_RESULT(no)]) 130 | fi], 131 | [Fortran 77], [if test x != x"$MPILIBS"; then 132 | AC_MSG_CHECKING([for mpif.h]) 133 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[ include 'mpif.h'])],[AC_MSG_RESULT(yes)], [MPILIBS="" 134 | AC_MSG_RESULT(no)]) 135 | fi], 136 | [Fortran], [if test x != x"$MPILIBS"; then 137 | AC_MSG_CHECKING([for mpif.h]) 138 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[ include 'mpif.h'])],[AC_MSG_RESULT(yes)], [MPILIBS="" 139 | AC_MSG_RESULT(no)]) 140 | fi]) 141 | 142 | AC_LANG_CASE([C], [CC="$ax_mpi_save_CC"], 143 | [C++], [CXX="$ax_mpi_save_CXX"], 144 | [Fortran 77], [F77="$ax_mpi_save_F77"], 145 | [Fortran], [FC="$ax_mpi_save_FC"]) 146 | 147 | AC_SUBST(MPILIBS) 148 | 149 | # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: 150 | if test x = x"$MPILIBS"; then 151 | $2 152 | : 153 | else 154 | ifelse([$1],,[AC_DEFINE(HAVE_MPI,1,[Define if you have the MPI library.])],[$1]) 155 | : 156 | fi 157 | ])dnl AX_MPI 158 | -------------------------------------------------------------------------------- /src/GenericTargetMachine.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __GENERICTARGETMACHINE_HPP__ 2 | #define __GENERICTARGETMACHINE_HPP__ 3 | 4 | #include 5 | #include "slots.hpp" 6 | #include "utility.hpp" 7 | 8 | /*! \class GenericTargetMachine 9 | 10 | A generic machine which supports an arbitrary number of registers, flags 11 | and memory. 12 | */ 13 | template 16 | class GenericTargetMachine : 17 | public TargetMachineWithFlags 18 | { 19 | public: 20 | /*! Initialise the the class, setting flags to 0. 21 | */ 22 | GenericTargetMachine() : 23 | TargetMachineWithFlags() 24 | { 25 | // TODO Implement (initialisation of memory) 26 | assert(!"TODO implement me."); 27 | } 28 | 29 | void initialiseRandom() 30 | { 31 | // TODO Implement (randomise memory) 32 | 33 | // Implement this by having a flag which says random is enabled, any 34 | // location which has not been written returns a random result. 35 | assert(!"TODO implement me."); 36 | } 37 | 38 | MemoryDataType getMemoryValue(MemoryAddressType address) 39 | { 40 | // TODO Implement (retreive memory) 41 | assert(!"TODO implement me."); 42 | return MemoryDataType(); 43 | } 44 | 45 | void setMemoryValue(MemoryAddressType address, MemoryDataType value) 46 | { 47 | // TODO Implement (set memory) 48 | assert(!"TODO implement me."); 49 | } 50 | 51 | bool equivalentState(TargetMachine &other) 52 | { 53 | // TODO Implement (check memory is equal) 54 | assert(!"TODO implement me."); 55 | } 56 | 57 | bool containsState(TargetMachine &other, 58 | std::vector> *mapping=nullptr) 59 | { 60 | // TODO Implement 61 | // First call TargetMachine::containsState 62 | // Then perform a similar analysis with memory 63 | assert(!"TODO implement me."); 64 | } 65 | 66 | protected: 67 | 68 | // TODO implement memory as a list of reads and writes, rather than an 69 | // actual array of items. 70 | }; 71 | 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /src/Instruction.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __INSTRUCTION_HPP__ 2 | #define __INSTRUCTION_HPP__ 3 | 4 | #include 5 | #include "slots.hpp" 6 | #include "utility.hpp" 7 | 8 | class Slot; 9 | class TargetMachineBase; 10 | class Backend; 11 | 12 | /*! \class Instruction 13 | 14 | The Instruction base class is intended to be subclassed by instructions 15 | that the target processor provides. The execute function, and getSlots are 16 | the most critical, since they provide the actual implementation of the 17 | instruction. The other methods allow instructions to be printed and 18 | parsed. 19 | 20 | The entire instructions classes can be generated by the generate.py. 21 | */ 22 | class Instruction 23 | { 24 | public: 25 | virtual ~Instruction() {}; 26 | 27 | /*! The execution function provides an implementation of the instruction, 28 | applying to the passed in machine. The slots are used to indicate 29 | which registers, and constants the instruction should use, etc. The 30 | function should return the number of slots used by the instruction. 31 | 32 | An example of the and instruction for AVR is given below. 33 | \code 34 | // Cast the given MachineTarget to the correct type 35 | AvrMachine *mach = static_cast(_mach); 36 | 37 | // Retrieve register 38 | uint8_t rA = mach->getRegister(slots[0]); 39 | uint8_t rB = mach->getRegister(slots[1]); 40 | 41 | // Perform the operation, set flags 42 | rA = rA & rB; 43 | setFlagSVNZ(mach, rA, 0); 44 | 45 | // Set registers 46 | mach->setRegister(slots[0], rA); 47 | 48 | return 2; 49 | \endcode 50 | 51 | @param _mach The machine state, which will be modified as per the 52 | operation of the instruction. 53 | @param slots The first slot to be used by the instruction. Normally 54 | the list of slots would have been composed of the 55 | result of getSlots, with the appropriate pointer to 56 | the list passed in here. 57 | @return The number of slots used by the instruction (same as 58 | getNumberOfSlots). 59 | */ 60 | virtual unsigned execute(TargetMachineBase *_mach, Slot **slots) = 0; 61 | 62 | /*! Return a list of slots used by the instruction. 63 | 64 | The function allocates the correct number and type of slots for the 65 | instruction. These are then owned by the callee, and must be 66 | deallocated. 67 | 68 | For example, a three operand add instruction would return three slots, 69 | each derived from RegisterSlot. 70 | 71 | @return A list of slots which the instruction operates on. 72 | 73 | */ 74 | virtual std::vector getSlots() {return {};} 75 | 76 | /*! Return the number of slots that the instruction operates on. 77 | 78 | @return The number of slots that the instruction's execute method 79 | requires. 80 | */ 81 | virtual unsigned getNumberOfSlots() {return 0;} 82 | 83 | 84 | virtual std::string toString() { return ""; } 85 | 86 | /*! Represent the instruction as a string. 87 | 88 | E.g. "add r0, r1, r3", if the slots had the values 0, 1 and 3. 89 | 90 | @param slots The slots the instruction requires. 91 | @return A string with a textual representation of the 92 | instruction. 93 | */ 94 | virtual std::string toString(Slot **slots) { return "";} 95 | 96 | /*! Return a string with the instruction mnemonic. 97 | 98 | E.g. "add" 99 | 100 | @return The instruction mnemonic. 101 | */ 102 | virtual std::string getName() { return "";} 103 | 104 | 105 | /*! Construct a list of slots based on a string. 106 | 107 | The parse function attempts to use the instruction's format to 108 | determine whether a string matches the instruction. It also extracts 109 | values for each of the slots used by the instruction, if there is a 110 | match. 111 | 112 | For example, with the input "add r1, r3, r2", the instruction will 113 | attempt to match "add", then read three values into slots: 1, 3, 2. If 114 | the function could not parse the string, false is returned. 115 | 116 | @param input The string to parse as an instruction. 117 | @param slotlist The list to place the recorded slot values in. 118 | @return Whether or not the instruction could be parsed, 119 | and the slotlist contents are valid. 120 | */ 121 | virtual bool parse(std::string input, std::vector &slotlist) { return false;}; 122 | }; 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /src/TargetMachine.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __TARGETMACHINE_H__ 2 | #define __TARGETMACHINE_H__ 3 | 4 | class TargetMachineBase 5 | { 6 | 7 | }; 8 | 9 | /*! \class TargetMachine 10 | 11 | This class holds the state of the processor - the register values. Each 12 | register also has a written and read bit associated with it, recording 13 | whether it has been read or changed. Methods are provided for accessing 14 | each, as well as comparing the state to other states. The class is 15 | templated, accepting a type for the registers and a number of registers 16 | for this state. 17 | 18 | This class is designed to be subclassed and customised for a specific 19 | processor. 20 | */ 21 | template 22 | class TargetMachine : public TargetMachineBase 23 | { 24 | public: 25 | /*! Construct the target machine 26 | 27 | Set all registers to zero, and mark all registers as not read and not 28 | written. 29 | */ 30 | TargetMachine() 31 | { 32 | for(unsigned i = 0; i < NumberOfRegisters; ++i) 33 | { 34 | registers[i] = 0; 35 | register_written[i] = false; 36 | register_read[i] = false; 37 | } 38 | } 39 | 40 | /*! Initialise the state of the TargetMachine to random. 41 | 42 | All registers are marked as unread and unwritten, and set to a random 43 | value. 44 | */ 45 | void initialiseRandom() 46 | { 47 | for(int i = 0; i < NumberOfRegisters; ++i) 48 | { 49 | registers[i] = (RegisterType) rand(); 50 | register_written[i] = false; 51 | register_read[i] = false; 52 | } 53 | } 54 | 55 | /*! Get the value of a register, specified by a slot. 56 | 57 | @param reg A slot whose value is the register index 58 | @return The value of the register. 59 | */ 60 | RegisterType getRegister(Slot *reg) 61 | { 62 | register_read[reg->getValue()] = true; 63 | return registers[reg->getValue()]; 64 | } 65 | 66 | /*! Set the value of a register, specified by a slot. 67 | 68 | @param reg The register to set. 69 | @param value The value to set the register to. 70 | */ 71 | void setRegister(Slot *reg, RegisterType value) 72 | { 73 | register_written[reg->getValue()] = true; 74 | registers[reg->getValue()] = value; 75 | } 76 | 77 | /*! Get the value of a register, by register number. 78 | 79 | @param reg The number of the register. 80 | @return The value of the register. 81 | */ 82 | RegisterType getRegisterValue(unsigned reg) 83 | { 84 | register_read[reg] = true; 85 | return registers[reg]; 86 | } 87 | 88 | /*! Set the value of a register, by register number. 89 | 90 | @param reg The number of the register. 91 | @param value The value to set the register to. 92 | */ 93 | void setRegisterValue(unsigned reg, RegisterType value) 94 | { 95 | register_written[reg] = true; 96 | registers[reg] = value; 97 | } 98 | 99 | /*! Perform a simple check to determine whether another TargetMachine is the 100 | same as this one. This is not commutative, since it only checks the 101 | registers marked as written in this state. 102 | 103 | For example: 104 | \code 105 | Current machine state: 106 | r0 = 10, r1 = 20 107 | Other machine state: 108 | r0 = 10, r1 = 20, r2 = 30 109 | \endcode 110 | The other state is equivalent, since only r0 and r1 are checked. 111 | 112 | \code 113 | Current machine state: 114 | r0 = 10, r1 = 20, r2 = 20 115 | Other machine state: 116 | r0 = 10, r1 = 20 117 | \endcode 118 | The other state is not equivalent, since r0, r1 and r2 are checked. 119 | 120 | @param other The state to check equivalence to. 121 | @return Whether or not the states are equivalent. 122 | */ 123 | bool equivalentState(TargetMachine &other) 124 | { 125 | bool equiv = true; 126 | 127 | for(unsigned i = 0; i < NumberOfRegisters; ++i) 128 | if(register_written[i] && registers[i] != other.registers[i]) 129 | equiv = false; 130 | 131 | return equiv; 132 | } 133 | 134 | /*! Check whether the other state is contained within the current state. 135 | 136 | This attempts to find out whether there is a permutation of written 137 | registers in the current state which corresponds to the other state. 138 | This means that as long as the other register values are amongst the 139 | written values in our current state, the result is true. The function 140 | computes a mapping between the current registers and the other 141 | registers. 142 | 143 | If a mapping is already specified, then it just checks the state is 144 | contained, as per that mapping. This allows the mapping to be computed 145 | at first, and then used in subsequent calls, preserving the register 146 | mapping. 147 | 148 | For example: 149 | \code 150 | Current machine state: 151 | r0 = 10, r1 = 20 152 | Other machine state: 153 | r4 = 20 154 | \endcode 155 | r4 can be mapped onto r1, therefore the current state contains 156 | state other. 157 | 158 | The function checks that the current state has atleast as many 159 | register written as the other state. If the current state has N 160 | registers written and the other state has M register written, the 161 | number of combinations is N choose M. Each permutation of these M 162 | registers is then compared to see if a mapping can be found. 163 | 164 | TODO: next_permutation takes ~50% of this function's runtime, perhaps 165 | the combinations should be cached and reused. 166 | 167 | @param other The state to test whether it is a subset of the 168 | current state. 169 | @param mapping A mapping of this state's registers to the other 170 | state's registers. 171 | @return Whether the written registers in other can be mapped 172 | onto the current state. 173 | */ 174 | bool containsState(TargetMachine &other, 175 | std::vector> *mapping=nullptr) 176 | { 177 | RegisterType reg_map[NumberOfRegisters]; 178 | RegisterType reg_map_other[NumberOfRegisters]; 179 | unsigned n_reg=0, n_reg_other=0; 180 | bool equiv; 181 | 182 | // If a mapping is specified, don't try to find one, just compare 183 | if(mapping && mapping->size() != 0) 184 | { 185 | for(auto &map: *mapping) 186 | { 187 | if(registers[map.first] != other.registers[map.second] || 188 | !register_written[map.first] || !other.register_written[map.second]) 189 | { 190 | return false; 191 | } 192 | } 193 | return true; 194 | } 195 | 196 | // Fill in the array with the registers that are written 197 | for(unsigned i = 0; i < NumberOfRegisters; ++i) 198 | { 199 | if(register_written[i]) 200 | { 201 | reg_map[n_reg++] = i; 202 | } 203 | if(other.register_written[i]) 204 | { 205 | reg_map_other[n_reg_other++] = i; 206 | } 207 | } 208 | 209 | // If the other state requires more registers than we have, then the 210 | // states cannot be equivalent. 211 | if(n_reg_other > n_reg || n_reg_other == 0) 212 | return false; 213 | 214 | std::vector rm(reg_map, reg_map+n_reg); 215 | Combinations comb_iter(rm.size(), n_reg_other); 216 | std::vector reg_list; 217 | 218 | // Iterate over each combination of n_reg_other registers from our 219 | // register list. 220 | do 221 | { 222 | comb_iter.getSelection(reg_list); 223 | 224 | // Iterate over each permutation of the chosen combination. 225 | do 226 | { 227 | // Check if all the registers match. If they do, then we have 228 | // found a mapping. If mapping is not null, record this. 229 | equiv = true; 230 | for(unsigned i = 0; i < n_reg_other; ++i) 231 | { 232 | if(registers[reg_map[reg_list[i]]] != other.registers[reg_map_other[i]]) 233 | equiv = false; 234 | } 235 | if(equiv) 236 | { 237 | if(mapping) 238 | for(unsigned i = 0; i < n_reg_other; ++i) 239 | mapping->push_back(std::make_pair(reg_map[reg_list[i]], reg_map_other[i])); 240 | break; 241 | } 242 | } while(std::next_permutation(reg_list.begin(), reg_list.end())); 243 | if(equiv) 244 | break; 245 | } while(comb_iter.next()); 246 | 247 | return equiv; 248 | } 249 | 250 | protected: 251 | RegisterType registers[NumberOfRegisters]; 252 | bool register_written[NumberOfRegisters]; 253 | bool register_read[NumberOfRegisters]; 254 | }; 255 | 256 | 257 | 258 | #endif 259 | -------------------------------------------------------------------------------- /src/TargetMachineWithFlags.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __TARGETMACHINEWITHFLAGS_HPP__ 2 | #define __TARGETMACHINEWITHFLAGS_HPP__ 3 | 4 | #include 5 | #include "slots.hpp" 6 | #include "utility.hpp" 7 | 8 | #include "TargetMachine.hpp" 9 | 10 | /*! \class TargetMachineWithFlags 11 | 12 | This class extends the TargetMachine class to handle an arbitrary number 13 | of processor flags. 14 | */ 15 | template 16 | class TargetMachineWithFlags : public TargetMachine 17 | { 18 | public: 19 | /*! Initialise the the class, setting flags to 0. 20 | */ 21 | TargetMachineWithFlags() : TargetMachine() 22 | { 23 | for(unsigned i = 0; i < NumberOfFlags; ++i) 24 | flags[i] = false; 25 | 26 | } 27 | 28 | /*! Set the value of the flags randomly. 29 | 30 | This overrides the initialiseRandom function of TargetMachine, also 31 | providing randomised flags. 32 | 33 | */ 34 | void initialiseRandom() 35 | { 36 | TargetMachine::initialiseRandom(); 37 | 38 | for(int i = 0; i < NumberOfFlags; ++i) 39 | { 40 | flags[i] = rand() & 1; 41 | } 42 | } 43 | 44 | /*! Get the value of a flag 45 | 46 | @param flg The flag to return the value of. 47 | @return The value of the flag. 48 | */ 49 | bool getFlagValue(unsigned flg) 50 | { 51 | return flags[flg]; 52 | } 53 | 54 | /*! Set the value of a flag 55 | 56 | @param flg The flag to set the value of 57 | @param value The value to set to. 58 | */ 59 | void setFlagValue(unsigned flg, bool value) 60 | { 61 | flags[flg] = value; 62 | } 63 | 64 | // bool equivalentState(TargetMachineWithFlags &other) 65 | // { 66 | // assert(!"TODO implement me."); 67 | // return false; 68 | // } 69 | 70 | protected: 71 | bool flags[NumberOfFlags]; 72 | // TODO possible extension: read and write status for flags 73 | }; 74 | 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /src/algorithms/bruteforce.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __BRUTEFORCE_H__ 2 | #define __BRUTEFORCE_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /*! Iterate over all possible combinations. 9 | 10 | This function iterates over every possible combination of the values in 11 | each entry of the values container. 12 | 13 | Example: 14 | vector> vals = {{0,1,2}, {3,4}}; 15 | 16 | vector::iterator> current; 17 | current.push_back(vals[0].begin()); 18 | current.push_back(vals[1].begin()); 19 | 20 | do { 21 | ... 22 | } while(bruteforceIterate(values, current)); 23 | 24 | The following values will be in current: 25 | 0, 3 26 | 0, 4 27 | 1, 3 28 | 1, 4 29 | 2, 3 30 | 2, 4 31 | 32 | @param containers A list of containers, each containing a set of values. 33 | @param iterators A list of iterators. Each iterator is derived from the 34 | corresponding container. 35 | @return True if there are further values to iterate. 36 | 37 | */ 38 | template 39 | bool bruteforceIterate(std::vector &containers, 40 | std::vector &iterators) 41 | { 42 | assert(containers.size() == iterators.size()); 43 | 44 | for(int i = iterators.size()-1; i >= 0; --i) 45 | { 46 | iterators[i]++; 47 | 48 | if(iterators[i] == containers[i].end()) 49 | { 50 | iterators[i] = containers[i].begin(); 51 | } 52 | else 53 | { 54 | return true; 55 | } 56 | } 57 | 58 | return false; 59 | } 60 | 61 | /*! Iterate over all possible combinations. 62 | 63 | This function iterates over every possible combination of the values. 64 | There is no list of containers in this version, allowing just a single 65 | container to be passed, if all entries in the iterator list are derived 66 | from the same container. 67 | 68 | Example: 69 | vector vals = {0,1,2}; 70 | 71 | vector::iterator> current; 72 | 73 | current.push_back(vals.begin()); 74 | current.push_back(vals.begin()); 75 | 76 | do { 77 | ... 78 | } while(bruteforceIterate(values, current)); 79 | 80 | The following values will be in current: 81 | 0, 0 82 | 0, 1 83 | 0, 2 84 | 1, 0 85 | 1, 1 86 | ... 87 | 88 | @param values A list of values. 89 | @param iterators A list of iterators. Each iterator is derived from values. 90 | @return True if there are further values to iterate. 91 | 92 | */ 93 | template 94 | bool bruteforceIterate(Container &values, 95 | std::vector &iterators) 96 | { 97 | for(int i = iterators.size()-1; i >= 0; --i) 98 | { 99 | iterators[i]++; 100 | 101 | if(iterators[i] == values.end()) 102 | { 103 | iterators[i] = values.begin(); 104 | } 105 | else 106 | { 107 | return true; 108 | } 109 | } 110 | 111 | return false; 112 | } 113 | 114 | /*! Iterate over all possible combinations. 115 | 116 | This function accepts a generic iterator class, as long as the class has a 117 | next function. The next function advances the iterator to the next value, 118 | reseting it to the first if the last value has been reached. If a reset 119 | occurs, false is returned. This allows bruteforce iterating over other 120 | iterators, such as canonicalIterators and constantIterators. 121 | 122 | @param iterators A list of iterators 123 | @return True if there are further values to iterate. 124 | */ 125 | template 126 | bool bruteforceIterate(std::vector &iterators) 127 | { 128 | for(int i = iterators.size()-1; i >= 0; --i) 129 | { 130 | if(iterators[i].next()) 131 | { 132 | return true; 133 | } 134 | } 135 | 136 | return false; 137 | } 138 | 139 | /*! Iterate over all possible combinations. 140 | 141 | This function accepts a generic iterator class, as long as the class has a 142 | next function. The next function advances the iterator to the next value, 143 | reseting it to the first if the last value has been reached. If a reset 144 | occurs, false is returned. This allows bruteforce iterating over other 145 | iterators, such as canonicalIterators and constantIterators. 146 | 147 | @param iterators A list of iterators 148 | @return True if there are further values to iterate. 149 | */ 150 | template 151 | bool bruteforceIterate(std::vector &iterators) 152 | { 153 | for(int i = iterators.size()-1; i >= 0; --i) 154 | { 155 | if(iterators[i]->next()) 156 | { 157 | return true; 158 | } 159 | } 160 | 161 | return false; 162 | } 163 | 164 | #endif 165 | -------------------------------------------------------------------------------- /src/algorithms/bruteforceByCost.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __BRUTEFORCEBYCOST_HPP__ 2 | #define __BRUTEFORCEBYCOST_HPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /*! \class bruteforceByCost 10 | 11 | The class attempts to bruteforce a combination of containers, in ascending 12 | cost order. This class accepts a list of containers, a list of iterators 13 | to each container, and a cost function. The cost function gives the 'cost' 14 | of each list of iterators. 15 | 16 | Example: 17 | \code 18 | vector> list_of_values = { 19 | {0,1,2,3}, 20 | {0,1,2,3}, 21 | }; 22 | vector::iterator> list_of_iterators; 23 | 24 | bruteforceByCost> bfbc(list_of_values, 25 | list_of_iterators, 26 | [] (vector::iterator> ¤t) 27 | { 28 | int i = 0; 29 | 30 | for(auto &it: current) 31 | i += *it; 32 | 33 | return i; 34 | }); 35 | 36 | // Initial set in list_of_iterators 37 | bfbc.next(); 38 | // Next set is now in list_of_iterators 39 | bfbc.next(); 40 | // Next set is now in list_of_iterators 41 | ... 42 | \endcode 43 | 44 | The above code specifies that there are two lists, to be bruteforced 45 | (i.e. cross product of both), therefore the following sequence would 46 | be obtained with a standard bruteforce. 47 | \code 48 | (0,0) 49 | (0,1) 50 | (0,2) 51 | (0,3) 52 | (1,0) 53 | (1,1) 54 | (1,2) 55 | ... 56 | \endcode 57 | 58 | However, the cost function given to bruteforceByCost specifies that 59 | the 'cost' of a sequence is given by the sum of its values. Therefore 60 | the sequence of iteration is: 61 | \code 62 | (0,0) 63 | (0,1) 64 | (1,0) 65 | (2,0) 66 | (1,1) 67 | (0,2) 68 | ... 69 | \endcode 70 | 71 | Overall the order of iteration over these two lists is: 72 | \code 73 | 0 2 5 9 74 | 1 4 8 12 75 | 3 7 11 14 76 | 6 10 13 15 77 | \endcode 78 | 79 | The class supports arbitrary cost functions, but does not initially 80 | bruteforce all possible combinations to find the lowest to start with. 81 | Instead, the current iterator is used (or initialise to the first element 82 | of each array), and each direction explored (in a flood fill style). The 83 | lowest cost found so far is returned each time next is called. 84 | */ 85 | template 86 | class bruteforceByCost 87 | { 88 | public: 89 | typedef std::vector CType; 90 | typedef std::vector IType; 91 | 92 | /*! Construct the iterator. 93 | 94 | This initialises the class, and puts the first valid value into the 95 | iterators reference passed in. 96 | 97 | @param containers_ A list of containers, for which the cross 98 | product should be bruteforced. 99 | @param iterators_ The vector in which the iterators should 100 | be placed. This will be initialised if 101 | initialiseIterator is true, otherwise it 102 | is assumed to contain the first tuple of 103 | elements from which to be iterated. 104 | @param costFunction_ A function which will return a cost, when 105 | passed a list of iterators. 106 | @param initialiseIterator Whether or not the iterators_ parameter 107 | passed in is initialised. 108 | */ 109 | bruteforceByCost(CType &containers_, IType &iterators_, 110 | std::function costFunction_, 111 | bool initialiseIterator=true) : 112 | containers(containers_), iterators(iterators_), 113 | costFunction(costFunction_) 114 | { 115 | 116 | if(initialiseIterator) 117 | { 118 | iterators.clear(); 119 | for(auto &c: containers) 120 | iterators.push_back(c.begin()); 121 | } 122 | 123 | past_edge.insert(iterators); 124 | add_next_edge(); 125 | } 126 | 127 | /*! Display a grid of the explored and to-be-explored edges stored. For debugging. 128 | */ 129 | void display() 130 | { 131 | for(auto x = containers[0].begin(); x != containers[0].end(); ++x) 132 | { 133 | for(auto y = containers[1].begin(); y != containers[1].end(); ++y) 134 | { 135 | IType iter = {x,y}; 136 | 137 | if(past_edge.count(iter) == 1) 138 | std::cout << "E"; 139 | else if(next_edge.count(iter) == 1) 140 | std::cout << "N"; 141 | else 142 | std::cout << "."; 143 | } 144 | std::cout << "\n"; 145 | } 146 | } 147 | 148 | /*! Compute the next item to be iterated. 149 | 150 | This function advances the iterator to the next item. 151 | 152 | TODO: this function should reset when it wraps around. 153 | 154 | @return True if there are more values to iterate over. 155 | */ 156 | bool next() 157 | { 158 | if(next_edge.size() == 0) 159 | { 160 | return false; 161 | } 162 | else 163 | { 164 | auto next_key = min_element(next_edge.begin(), next_edge.end(), 165 | ComparePairSecond()); 166 | 167 | IType old_iterators = iterators; 168 | iterators = next_key->first; 169 | next_edge.erase(next_key); 170 | 171 | add_next_edge(); 172 | 173 | // For each connected iterator, check whether we should remove it 174 | // from the past edges. We can remove an iterator if itself has no 175 | // adjacent iterators in the next_edge. 176 | for(unsigned i = 0; i < containers.size(); ++i) 177 | for(int offset = -1; offset < 2; offset+=2) 178 | { 179 | IType current_connected = iterators; 180 | 181 | if(offset == -1 && current_connected[i] == containers[i].begin()) 182 | continue; 183 | 184 | current_connected[i] += offset; 185 | 186 | if(current_connected[i] == containers[i].end()) 187 | continue; 188 | 189 | bool is_in_next_edge = false; 190 | 191 | for(unsigned j = 0; j < containers.size(); ++j) 192 | for(int offset = -1; offset < 2; offset+=2) 193 | { 194 | IType test_edge = current_connected; 195 | 196 | if(offset == -1 && test_edge[j] == containers[j].begin()) 197 | continue; 198 | 199 | test_edge[j] += offset; 200 | 201 | if(test_edge[j] == containers[j].end()) 202 | continue; 203 | 204 | if(next_edge.count(test_edge) == 1) 205 | is_in_next_edge = true; 206 | } 207 | 208 | if(!is_in_next_edge && past_edge.count(current_connected)) 209 | { 210 | past_edge.erase(current_connected); 211 | } 212 | } 213 | 214 | past_edge.insert(iterators); 215 | 216 | return true; 217 | } 218 | } 219 | 220 | private: 221 | CType &containers; 222 | IType &iterators; 223 | std::function costFunction; 224 | 225 | std::map next_edge; 226 | std::set past_edge; 227 | 228 | // A class to compare the second value in a pair type. Used with the map 229 | // above to find the minimum value. 230 | struct ComparePairSecond 231 | { 232 | typedef typename std::map::value_type PType; 233 | bool operator()(PType a, PType b) const 234 | { 235 | return a.second < b.second; 236 | } 237 | }; 238 | 239 | /*! Add the adjacent iterators to the current iterator to the list of iterators 240 | to be explored. This is equivalent to four-way linkage in two 241 | dimensions. Each time called, it adds up to 2*containers.size() 242 | iterators to the list. 243 | */ 244 | void add_next_edge() 245 | { 246 | for(unsigned i = 0; i < containers.size(); ++i) 247 | for(int offset = -1; offset < 2; offset+=2) 248 | { 249 | IType current = iterators; 250 | 251 | if(offset == -1 && current[i] == containers[i].begin()) 252 | continue; 253 | 254 | current[i] += offset; 255 | 256 | if(current[i] == containers[i].end()) 257 | continue; 258 | 259 | if(past_edge.count(current) == 1) 260 | continue; 261 | 262 | next_edge[current] = costFunction(current); 263 | } 264 | } 265 | }; 266 | 267 | #endif 268 | -------------------------------------------------------------------------------- /src/algorithms/canonicalIterator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CANONICAL_H__ 2 | #define __CANONICAL_H__ 3 | 4 | #include "canonicalIteratorBasic.hpp" 5 | #include "canonicalIteratorGeneric.hpp" 6 | #include "canonicalIteratorLiveness.hpp" 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/algorithms/canonicalIteratorBasic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "canonicalIteratorBasic.hpp" 7 | 8 | using namespace std; 9 | 10 | canonicalIteratorBasic::canonicalIteratorBasic(vector &slotlist_, 11 | int pre_maximum_) 12 | { 13 | // We just want the slots which are RegisterSlots 14 | for(auto slot: slotlist_) 15 | { 16 | if(dynamic_cast(slot) != 0) 17 | slotlist.push_back((RegisterSlot*)slot); 18 | } 19 | pre_maximum = pre_maximum_; 20 | } 21 | 22 | bool canonicalIteratorBasic::next() 23 | { 24 | // Iterate from the last slot in the sequence. 25 | for(int i = slotlist.size()-1; i >= 0; i--) 26 | { 27 | auto rs_i = slotlist[i]; 28 | auto va_i = rs_i->getValidArguments(); 29 | 30 | int next = rs_i->getValue() + 1; 31 | 32 | // Calculate what the maximum value currently in the sequence is. 33 | int max = pre_maximum; 34 | for(int j = 0; j < i; ++j) 35 | { 36 | int val = slotlist[j]->getValue(); 37 | if(val > max) 38 | max = val; 39 | } 40 | 41 | // If the next value is too large, reset the current value and 42 | // continue with the next slot. Otherwise, we are done. 43 | if(next > max + 1) 44 | { 45 | rs_i->setValue(0); 46 | continue; 47 | } 48 | else 49 | { 50 | rs_i->setValue(next); 51 | return true; 52 | } 53 | } 54 | 55 | return false; 56 | } 57 | -------------------------------------------------------------------------------- /src/algorithms/canonicalIteratorBasic.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CANONICALITERATORBASIC_H__ 2 | #define __CANONICALITERATORBASIC_H__ 3 | 4 | #include 5 | #include 6 | #include "../slots.hpp" 7 | 8 | /*! \class canonicalIteratorBasic 9 | 10 | Iterate over canonical forms of registers in the given slots. This is a 11 | simplified form, which does not abide by the register classes specified in 12 | each register slot. The values in the register slots are such that all 13 | possible renamings have been iterated during the course of the iterator. 14 | 15 | Example of canonical form: 16 | \code 17 | 3 register slots 18 | 0 0 0 19 | 0 0 1 20 | 0 1 0 21 | 0 1 1 22 | 0 1 2 23 | 24 | 4 register slots 25 | 0 0 0 0 26 | 0 0 0 1 27 | 0 0 1 0 28 | 0 0 1 1 29 | 0 0 1 2 30 | ... 31 | \endcode 32 | 33 | The algorithm for computing the next set of values is simple. Each slot is 34 | considered consecutively and incremented. If the slot's value becomes 35 | greater than the max of the sequence + 1, the value is reset to 0 and the 36 | next slot considered. Otherwise the next set of values has been found. See 37 | the design document distributed with the toolkit for more details. 38 | 39 | The class also accepts a pre_maximum parameter. This parameter tells the 40 | iterator to assume there were pre_maximum number of additional slots 41 | before the slots given. For example, 3 register slots, passed with 42 | pre_maximum=1 gives the following sequence: 43 | \code 44 | 0 0 0 45 | 0 0 1 46 | 0 1 0 47 | 0 1 1 48 | 0 1 2 49 | 1 0 0 50 | 1 0 1 51 | 1 0 2 52 | ... 53 | \endcode 54 | This parameter allows the canonicalIteratorBasic class to be used to just 55 | iterate over functional register renamings, narrowing the search space 56 | before trying to map a matching sequence to a correct register assignment. 57 | See the design document for more details. 58 | 59 | */ 60 | class canonicalIteratorBasic 61 | { 62 | public: 63 | /*! Initialise the canonical iterator. 64 | 65 | Pick the RegisterSlots from the slotslist_ and store the pointers 66 | internally. 67 | 68 | @param slotlist_ A list of slots. The RegisterSlots out of this 69 | list are selected. 70 | @param pre_maximum_ Assume there are this number of extra slots 71 | before the given slots. 72 | */ 73 | canonicalIteratorBasic(std::vector &slotlist_, int pre_maximum_=-1); 74 | 75 | /*! Compute the next set of values in the canonical sequence. 76 | 77 | @return True if there are further values to iterate, false if the last 78 | value has already been iterated. 79 | */ 80 | bool next(); 81 | protected: 82 | std::vector slotlist; 83 | 84 | int pre_maximum; 85 | }; 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /src/algorithms/canonicalIteratorGeneric.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CANONICALITERATORGENERIC_H__ 2 | #define __CANONICALITERATORGENERIC_H__ 3 | 4 | #include 5 | #include 6 | #include "../slots.hpp" 7 | 8 | #include "canonicalIteratorBasic.hpp" 9 | 10 | /*! \class canonicalIteratorGeneric 11 | 12 | Iteratively generate values for registers slots. 13 | 14 | This iterator is similar to canonicalIteratorGeneric, except it accounts 15 | for the register classes specified by each RegisterSlot. 16 | 17 | */ 18 | 19 | class canonicalIteratorGeneric : public canonicalIteratorBasic 20 | { 21 | public: 22 | /*! Constructor that takes the list of slots used in the instruction 23 | sequence. 24 | 25 | The constructor extracts the RegisterSlots from the entire 26 | list and stores the pointers. 27 | 28 | @param slotlist_ List of pointers to register slots 29 | */ 30 | canonicalIteratorGeneric(std::vector &slotlist_); 31 | 32 | /*! Advance the stored RegisterSlots to the next sequence. 33 | 34 | @return True if the set sequence is valid, false if the sequence has 35 | wrapped around. 36 | */ 37 | bool next(); 38 | protected: 39 | bool computed_intersections; 40 | std::vector> class_intersections; 41 | std::vector canonical; 42 | unsigned max_class_size; 43 | 44 | /*! Perform a single standard canonical step. 45 | 46 | This performs a standard canonical step on the canonical variable. 47 | 48 | @return True if there are further values to enumerate. 49 | */ 50 | bool canonicalStep(); 51 | 52 | /*! Precompute the register classes for possible combinations of classes. 53 | 54 | This function precomputes the intersection of all combinations of 55 | register classes passed in. The result is stored in the 56 | class_intersections variable. For the index, each bit represents 57 | whether a particular register class is in the intersection or not. 58 | 59 | @param classes The list of register classes to compute intersections 60 | for. The number of classes is large: 2^classes.size() 61 | */ 62 | void precomputePossibleRegisters(std::vector> classes); 63 | }; 64 | 65 | /*! Attempt to map a set of values onto correct register classes. 66 | 67 | This function takes a set of values, which define the current registers of 68 | each slot. These need not be valid by the RegisterSlot::getValidArguments 69 | call, instead representing which slots must take the same register. 70 | 71 | The function uses this information and attempt to rename each register so 72 | that all registers satisfy the register class of each slot. 73 | 74 | The function also accepts a class_intersections parameter which allows 75 | some of the computation to be precomputed. This parameter must be a list 76 | of 2^N length, where N is the largest class ID given by a RegisterSlot. 77 | Each entry in the list must be the intersections of the classes identified 78 | by its index. The index has a bit set for each class ID. For example, the 79 | intersection of class IDs 0, 3 and 4 would be at index 0b00011001, or 25. 80 | 81 | @param slotlist The list of RegisterSlots to map onto correct 82 | values 83 | @param values A list of slot values which should be used 84 | with the slotlist. If this is not set, then 85 | the list of values is taken from each slot, 86 | via the standard Slot::getValue call. 87 | @param class_intersections If specified, this parameter has the 88 | precomputed intersections between all 89 | combinations of classes. If it is not 90 | specified, a slow method is used. However, 91 | this slower method can cope with RegisterSlots 92 | without a class ID assigned, or when the 93 | memory tradeoff to precompute would be 94 | extreme. 95 | */ 96 | std::pair,bool> canonicalMapping( 97 | std::vector &slotlist, 98 | std::vector values = {}, 99 | std::vector> *class_intersections=nullptr); 100 | 101 | /*! This function forwards to the RegisterSlot version of canonicalMapping. 102 | 103 | The RegisterSlots are extracted from the given slot list, and passed on to 104 | canonicalMapping. See canonicalMapping. 105 | 106 | @param slotlist The list of slots to map onto correct values. 107 | @param values A substitute list of values for the register 108 | slots. 109 | @param class_intersections A precomputed list of the register class 110 | intersections. See the other form of 111 | canonicalMapping for more details. 112 | 113 | */ 114 | std::pair,bool> canonicalMapping( 115 | std::vector &slotlist, 116 | std::vector values = {}, 117 | std::vector> *class_intersections=nullptr); 118 | 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /src/algorithms/canonicalIteratorLiveness.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "canonicalIteratorGeneric.hpp" 7 | #include "canonicalIteratorLiveness.hpp" 8 | 9 | using namespace std; 10 | 11 | canonicalIteratorLiveness::canonicalIteratorLiveness(vector &slotlist_, unsigned n_live_) 12 | : canonicalIteratorGeneric(slotlist_), n_live(n_live_) 13 | { 14 | } 15 | 16 | bool canonicalIteratorLiveness::next() 17 | { 18 | if(slotlist.size() == 0) // All slots have been excluded. 19 | { 20 | return false; 21 | } 22 | 23 | while(true) 24 | { 25 | bool found_next = canonicalStep(); 26 | 27 | if(!found_next) 28 | { 29 | for(unsigned i = 0; i < slotlist.size(); ++i) 30 | slotlist[i]->setValue(slotlist[i]->getValidArguments().front()); 31 | return false; 32 | } 33 | 34 | pair,bool> mapping; 35 | 36 | // Pass the class_intersections if we had well defined register classes. 37 | if(computed_intersections) 38 | mapping = canonicalMappingLive(slotlist, canonical, n_live, &class_intersections); 39 | else 40 | mapping = canonicalMappingLive(slotlist, canonical, n_live, nullptr); 41 | 42 | if(mapping.second) 43 | { 44 | for(unsigned i = 0; i < slotlist.size(); ++i) 45 | slotlist[i]->setValue(mapping.first[i]); 46 | return true; 47 | } 48 | } 49 | } 50 | 51 | 52 | 53 | // TODO: precompute register class intersections 54 | // TODO: explaination, comments 55 | // TODO: Investigate why this slows down with regular, but restricted classes 56 | // e.g {0-3}x8 slower than {0-7}x8 57 | pair,bool> canonicalMappingLive(vector &slotlist, 58 | vector values, unsigned n_live, 59 | vector> *class_intersections) 60 | { 61 | unsigned i = 0; 62 | vector possibilities(slotlist.size()); 63 | vector mapping(slotlist.size()); 64 | vector possibles; 65 | 66 | bool have_intersections=false; 67 | 68 | if(class_intersections != nullptr) 69 | have_intersections = true; 70 | 71 | // max of all classes 72 | vector mapping_count; 73 | 74 | unsigned largest_reg=0; 75 | for(auto slot: slotlist) 76 | { 77 | unsigned m = slot->getValidArguments().back(); 78 | 79 | if(m > largest_reg) 80 | largest_reg = m; 81 | } 82 | mapping_count.resize(largest_reg+1); 83 | 84 | vector current_live_reg, current_read_reg; 85 | 86 | current_live_reg.resize(largest_reg+1); 87 | current_read_reg.resize(largest_reg+1); 88 | 89 | if(values.size() != slotlist.size()) 90 | { 91 | values.clear(); 92 | values.resize(slotlist.size()); 93 | 94 | for(unsigned j = 0; j < slotlist.size(); ++j) 95 | values[j] = slotlist[j]->getValue(); 96 | } 97 | 98 | bool work = false; 99 | 100 | while(i < slotlist.size()) 101 | { 102 | auto mv = find(values.begin(), values.begin()+i, values[i]); 103 | if(i > 0 && mv != values.begin()+i) 104 | { 105 | if(possibilities[i] != -1) 106 | { 107 | int n = mv - values.begin(); 108 | mapping[i] = mapping[n]; 109 | mapping_count[mapping[i]]++; 110 | possibilities[i] = -1; 111 | i++; 112 | if(i >= slotlist.size()) 113 | { 114 | work = true; 115 | } 116 | continue; 117 | } 118 | else 119 | { 120 | if(i == 0) 121 | break; 122 | mapping_count[mapping[i-1]]--; 123 | possibilities[i] = 0; 124 | i--; 125 | continue; 126 | } 127 | } 128 | 129 | // For all slots with the same value as the current, calculate the 130 | // intersection of register classes, to compute a list of possible 131 | // remappings. The intersections are either precomputed, if the 132 | // register classes of each slot were known. Otherwise they are 133 | // computed on the fly (slower). 134 | 135 | if(have_intersections) 136 | { 137 | unsigned v = values[i]; 138 | unsigned idx=0; 139 | vector *possibles_ptr; 140 | 141 | // Each class id is represented by a single bit, bitwise-oring the 142 | // bits together forms the index into the array. 143 | for(unsigned j = 0; j < slotlist.size(); ++j) 144 | { 145 | if(values[j] == v) 146 | { 147 | idx |= 1 << slotlist[j]->getRegisterClassID(); 148 | } 149 | } 150 | 151 | possibles_ptr = &(*class_intersections)[idx]; 152 | possibles.clear(); 153 | 154 | const unsigned intersect_size = possibles_ptr->size(); 155 | possibles.reserve(intersect_size); 156 | 157 | // Once we have the intersections of the classes, we do not want 158 | // the registers which we have already remapped. Copy them into a 159 | // new vector, so we can leave the precomputed values untouched. 160 | 161 | // Calculate which registers are live, and which are read from, 162 | // this is a representation of the use and def sets. 163 | for(unsigned j = 0; j < i; ++j) 164 | if(slotlist[j]->isWriteSlot() && !slotlist[j]->isReadSlot()) 165 | current_live_reg[mapping[j]] = true; 166 | else 167 | current_read_reg[mapping[j]] = true; 168 | 169 | // From these two sets, calculate read_set - live_set. If the size 170 | // of this set is bigger than the number of live registers in, 171 | // then we have used too many registers and the sequence cannot be 172 | // valid. 173 | unsigned unlive = 0; 174 | for(unsigned j = 0; j < largest_reg+1; ++j) 175 | { 176 | if(current_read_reg[j] and not current_live_reg[j]) 177 | unlive++; 178 | } 179 | 180 | for(unsigned k=0; k < possibles_ptr->size(); ++k) 181 | { 182 | unsigned current_possible = (*possibles_ptr)[k]; 183 | 184 | if(mapping_count[current_possible] == 0) 185 | { 186 | bool is_live = false; 187 | 188 | // If the register is a write only slot, then we can always map it. 189 | if(slotlist[i]->isWriteSlot() && !slotlist[i]->isReadSlot()) 190 | is_live = true; 191 | // If the possible register is not live, then this 192 | // increases the number of live registers from the input 193 | // set that we use (the !current_live_reg[current_possible] 194 | // part). Check that this doesn't exceed the number of 195 | // possible live registers. 196 | else if(unlive + !current_live_reg[current_possible] <= n_live) 197 | is_live = true; 198 | 199 | if(is_live) 200 | possibles.push_back(current_possible); 201 | } 202 | } 203 | 204 | } 205 | else 206 | { 207 | vector possibles_; 208 | possibles_ = possibleRegisters(slotlist, values, i); 209 | 210 | // This code is mostly similar to above, but the above takes a 211 | // pointer to the precomputed vector - about 20% faster than copying. 212 | possibles.clear(); 213 | possibles.reserve(possibles_.size()); 214 | 215 | // TODO optimisation: flags for size>0, possiblities[i]>=size, var for possibilities[i]-th val, then break 216 | 217 | vector current_live_reg, current_read_reg; 218 | 219 | current_live_reg.resize(largest_reg+1); 220 | current_read_reg.resize(largest_reg+1); 221 | 222 | // Calculate which registers are live, and which are read from, 223 | // this is a representation of the use and def sets. 224 | for(unsigned j = 0; j < i; ++j) 225 | if(slotlist[j]->isWriteSlot() && !slotlist[j]->isReadSlot()) 226 | current_live_reg[mapping[j]] = true; 227 | else 228 | current_read_reg[mapping[j]] = true; 229 | 230 | // From these two sets, calculate read_set - live_set. If the size 231 | // of this set is bigger than the number of live registers in, 232 | // then we have used too many registers and the sequence cannot be 233 | // valid. 234 | unsigned unlive = 0; 235 | for(unsigned j = 0; j < largest_reg+1; ++j) 236 | { 237 | if(current_read_reg[j] and not current_live_reg[j]) 238 | unlive++; 239 | } 240 | 241 | for(unsigned k=0; k < possibles_.size(); ++k) 242 | if(mapping_count[possibles_[k]] == 0) 243 | { 244 | bool is_live = false; 245 | 246 | // If the register is a write only slot, then we can always map it. 247 | if(slotlist[i]->isWriteSlot() && !slotlist[i]->isReadSlot()) 248 | is_live = true; 249 | // If the possible register is not live, then this 250 | // increases the number of live registers from the input 251 | // set that we use (the !current_live_reg[possibles_[k]] 252 | // part). Check that this doesn't exceed the number of 253 | // possible live registers. 254 | else if(unlive + !current_live_reg[possibles_[k]] <= n_live) 255 | is_live = true; 256 | 257 | if(is_live) 258 | possibles.push_back(possibles_[k]); 259 | } 260 | } 261 | 262 | if(possibles.size() == 0) 263 | { 264 | if(i == 0) 265 | break; 266 | mapping_count[mapping[i-1]]--; 267 | possibilities[i] = 0; 268 | i--; 269 | continue; 270 | } 271 | 272 | // We return to the previous value if we have exceeded the number of 273 | // possibles, or if we have tested more values than there are 274 | // positions left. The latter condition is a speed up - if it is not 275 | // there, large classes will be explored full, making this function 276 | // take up to seconds (!) to execute. 277 | if(possibilities[i] >= (int) possibles.size() || possibilities[i] > (int)(possibilities.size() - i)) 278 | { 279 | if(i == 0) 280 | break; 281 | mapping_count[mapping[i-1]]--; 282 | possibilities[i] = 0; 283 | i--; 284 | continue; 285 | } 286 | 287 | mapping[i] = possibles[possibilities[i]]; 288 | mapping_count[mapping[i]]++; 289 | possibilities[i]++; 290 | i++; 291 | if(i >= slotlist.size()) 292 | { 293 | work = true; 294 | } 295 | } 296 | 297 | return make_pair(mapping, work); 298 | } 299 | -------------------------------------------------------------------------------- /src/algorithms/canonicalIteratorLiveness.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CANONICALITERATORLIVENESS_H__ 2 | #define __CANONICALITERATORLIVENESS_H__ 3 | 4 | 5 | #include 6 | #include 7 | #include "../slots.hpp" 8 | 9 | #include "canonicalIteratorGeneric.hpp" 10 | 11 | class canonicalIteratorLiveness : public canonicalIteratorGeneric 12 | { 13 | public: 14 | canonicalIteratorLiveness(std::vector &slotlist_, unsigned live_registers); 15 | 16 | bool next(); 17 | private: 18 | unsigned n_live; 19 | }; 20 | 21 | std::vector possibleRegisters(std::vector &slotlist, std::vector &values, unsigned loc); 22 | 23 | std::pair,bool> canonicalMappingLive(std::vector &slotlist, std::vector values, 24 | unsigned live_registers, 25 | std::vector> *class_intersections=nullptr); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/algorithms/constantIterator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "constantIterator.hpp" 3 | #include "bruteforce.hpp" 4 | 5 | using namespace std; 6 | 7 | constantIterator::constantIterator(vector &slotlist_) 8 | { 9 | for(auto slot: slotlist_) 10 | { 11 | // See if any of the slots are ConstantSlots. If they are, reset them 12 | // and store the points in our own list. 13 | if(dynamic_cast(slot) != 0) 14 | { 15 | slotlist.push_back((ConstantSlot*)slot); 16 | slot->reset(); 17 | } 18 | } 19 | } 20 | 21 | void constantIterator::setLossy(bool lossy) 22 | { 23 | // Set the lossy bit on all slots. Reset them to their first value (not 24 | // strictly necessary, since iteratorSkip does this). 25 | for(auto slot: slotlist) 26 | { 27 | slot->iteratorSkip(lossy); 28 | slot->reset(); 29 | } 30 | } 31 | 32 | bool constantIterator::next() 33 | { 34 | // Iterate over all the slots we have 35 | return bruteforceIterate(slotlist); 36 | } 37 | -------------------------------------------------------------------------------- /src/algorithms/constantIterator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CONSTANTITERATOR_H__ 2 | #define __CONSTANTITERATOR_H__ 3 | 4 | #include 5 | #include "../slots.hpp" 6 | 7 | /*! \class constantIterator 8 | 9 | A class for iterating over constants. Currently this doesn't do much more 10 | than just store a list of ConstantSlots, and setting the lossy bit in them 11 | all at the same time. 12 | 13 | TODO: Should the logic for constant slot lossiness be moved into this 14 | class, just as there are separate iterators for RegisterSlots? 15 | */ 16 | class constantIterator 17 | { 18 | public: 19 | /*! Initialise the constant iterator 20 | 21 | This constructor takes a list of slots, and copies the pointers to 22 | constant slots into an internal array, which is used for iteration. 23 | 24 | @param slotlist_ A list of slots which may or may not contain 25 | ConstantSlots to iterate over. 26 | */ 27 | constantIterator(std::vector &slotlist_); 28 | 29 | /*! Set the lossy bit on the constant slots. 30 | 31 | The lossy bit restricts the range of the constant slots to some 32 | constants which are thought to be used more frequently than others. 33 | See ConstantSlot::iteratorSkip for more details. 34 | 35 | @param lossy Whether or not to enable the lossy mode. 36 | */ 37 | void setLossy(bool lossy); 38 | 39 | /*! Advance to the next constant 40 | 41 | This function goes through all the constant slots, iterating over 42 | every combination of values. If the full sequence has been iterated, 43 | false is returned. 44 | 45 | @return Whether the iterator still has values left to iterate 46 | over. 47 | */ 48 | bool next(); 49 | private: 50 | std::vector slotlist; 51 | }; 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/algorithms/test.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __TEST_H__ 2 | #define __TEST_H__ 3 | 4 | #include 5 | #include 6 | #include "../frontend.hpp" 7 | #include "../slots.hpp" 8 | 9 | /*! Execute a sequence of instructions, with the specified slots. 10 | 11 | This function simply iterates over the sequence of instructions, calling 12 | the execute method of each instruction, and passing the appropriate slots. 13 | In future, when branch instructions are implemented this will have to 14 | execute the instructions in a smarter order. 15 | 16 | @param insns A list of the instructions to be executed. 17 | @param slots A corresponding list of slots which the instructions 18 | accept. 19 | @param state The state on which to execute the instructions. 20 | */ 21 | template 22 | void executeSequence(std::vector &insns, std::vector &slots, 23 | Machine &state) 24 | { 25 | auto current_slot = &slots[0]; 26 | 27 | for(auto insn: insns) 28 | { 29 | auto n = insn->execute(&state, current_slot); 30 | current_slot += n; 31 | } 32 | } 33 | 34 | /*! Test the equivalence of an instruction sequence, when given an initial state 35 | and expected state. Permutations of the state will be checked, i.e. if the 36 | result was expected in r0, but actually appeared in r1, the state will be 37 | accepted. See TargetMachine::containsState for more details. 38 | 39 | This function is mostly a simple forwarder to executeSequence and 40 | containsState. 41 | 42 | TODO maybe this function should accept a register_mapping parameter. 43 | 44 | @param insns The instruction sequence. 45 | @param slots The list of slots. 46 | @param initial The initial test vector. 47 | @param expected The expected machine state. 48 | @param register_mapping A mapping between registers for the sequence 49 | under test. See TargetMachine::containsState 50 | for more information. 51 | @return Is the state obtained when applying the 52 | instructions to the initial parameter 53 | contained within the expected state. 54 | */ 55 | template 56 | bool testEquivalence(std::vector &insns, std::vector &slots, 57 | Machine &initial, Machine &expected, 58 | std::vector> *register_mapping=nullptr) 59 | { 60 | Machine test_state; 61 | 62 | test_state = initial; 63 | 64 | executeSequence(insns, slots, test_state); 65 | 66 | return test_state.containsState(expected, register_mapping); 67 | } 68 | 69 | /*! As with the previous version of testEquivalence, this tests a single test 70 | vector, however it derives the test vector from an arbitrary 71 | transformation function, and an initial state. 72 | 73 | TODO maybe this function should accept a register_mapping parameter. 74 | 75 | @param insns The instruction sequence. 76 | @param slots The list of slots. 77 | @param initial The initial test vector. 78 | @param transform A function which takes a machine state, and 79 | modifies it. 80 | @param register_mapping A mapping between registers for the sequence 81 | under test. See TargetMachine::containsState 82 | for more information. 83 | @return Is the state obtained when applying the 84 | instructions to the initial parameter 85 | contained within the expected state. 86 | */ 87 | template 88 | bool testEquivalence(std::vector &insns, std::vector &slots, 89 | Machine &initial, std::function transform, 90 | std::vector> *register_mapping=nullptr) 91 | { 92 | Machine transformed = initial; 93 | transform(transformed); 94 | 95 | return testEquivalence(insns, slots, initial, transformed, register_mapping); 96 | } 97 | 98 | /*! This form of testEquivalence takes two instruction sequences, and compares 99 | them to each other. A register mapping parameter is also given, and passed 100 | to containsState. This allows the function's use in testing multiple 101 | times, while respecting the register assignments found. This avoids 102 | problems where each random test vector can be matched in some way, but 103 | requiring different register assignments. 104 | 105 | @param insns The instruction sequence under test. 106 | @param slots Slots for the instruction sequence under test. 107 | @param reference_insns The reference sequence (sequence to be 108 | matched). 109 | @param reference_slots The slots for the reference sequence. 110 | @param register_mapping A mapping between registers for the sequence 111 | under test. See TargetMachine::containsState 112 | for more information. 113 | @return Is the state obtained when applying the 114 | instructions to the initial parameter 115 | contained within the expected state. 116 | */ 117 | template 118 | bool testEquivalence(std::vector &insns, std::vector &slots, 119 | std::vector &reference_insns, std::vector &reference_slots, 120 | std::vector> *register_mapping=nullptr) 121 | { 122 | // First do the instruction sequence under test 123 | Machine test_state; 124 | Machine reference_state; 125 | 126 | test_state.initialiseRandom(); 127 | reference_state = test_state; 128 | 129 | // Execute the sequence under test 130 | executeSequence(insns, slots, test_state); 131 | 132 | // Execute the reference sequence 133 | executeSequence(reference_insns, reference_slots, reference_state); 134 | 135 | return test_state.containsState(reference_state, register_mapping); 136 | } 137 | 138 | 139 | /*! Test the equivalence of an instruction seqence with another instruction 140 | sequence multiple times to see if they could be equivalent. Note that 141 | parameters are not commutative: since it is possible that the instruction 142 | sequence under test could produce unneccesary side effect, these can be 143 | ignored and the sequence still considered equivalent. 144 | 145 | @param insns The instruction sequence under test. 146 | @param slots Slots for the instruction sequence under test. 147 | @param reference_insns The reference sequence (sequence to be 148 | matched). 149 | @param reference_slots The slots for the reference sequence. 150 | @param number The number of test vectors to apply to the 151 | sequences. 152 | @return Is the state obtained when applying the 153 | instructions to the initial parameter 154 | contained within the expected state. 155 | */ 156 | template 157 | bool testEquivalenceMultiple(std::vector &insns, 158 | std::vector &slots, std::vector reference_insns, 159 | std::vector reference_slots, unsigned number=100) 160 | { 161 | std::vector> mapping; 162 | 163 | for(unsigned i = 0; i < number; ++i) 164 | { 165 | if(!testEquivalence(insns, slots, reference_insns, reference_slots, &mapping)) 166 | return false; 167 | } 168 | 169 | return true; 170 | } 171 | 172 | /*! Test the equivalence of an instruction seqence with another instruction 173 | sequence multiple times to see if they could be equivalent. Note that 174 | parameters are not commutative: since it is possible that the instruction 175 | sequence under test could produce unneccesary side effect, these can be 176 | ignored and the sequence still considered equivalent. 177 | 178 | @param insns The instruction sequence under test. 179 | @param slots Slots for the instruction sequence under test. 180 | @param reference_insns The reference sequence (sequence to be 181 | matched). 182 | @param reference_slots The slots for the reference sequence. 183 | @param number The number of test vectors to apply to the 184 | sequences. 185 | @return Is the state obtained when applying the 186 | instructions to the initial parameter 187 | contained within the expected state. 188 | */ 189 | template 190 | bool testEquivalenceMultiple(std::vector &insns, 191 | std::vector &slots, std::function transform, 192 | unsigned number=100) 193 | { 194 | std::vector> mapping; 195 | 196 | for(unsigned i = 0; i < number; ++i) 197 | { 198 | Machine initial; 199 | initial.initialiseRandom(); 200 | if(!testEquivalence(insns, slots, initial, transform, &mapping)) 201 | return false; 202 | } 203 | 204 | return true; 205 | } 206 | 207 | #endif 208 | -------------------------------------------------------------------------------- /src/frontend.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __FRONTEND_HPP__ 2 | #define __FRONTEND_HPP__ 3 | 4 | #include 5 | #include "slots.hpp" 6 | #include "utility.hpp" 7 | 8 | #include "Instruction.hpp" 9 | 10 | #include "TargetMachine.hpp" 11 | #include "TargetMachineWithFlags.hpp" 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/frontends/avr.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __AVR_HPP__ 2 | #define __AVR_HPP__ 3 | 4 | #include "../frontend.hpp" 5 | #include "../slots.hpp" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | std::vector> Avr_getAutogeneratedInstructionFactories(); 16 | 17 | class AvrRegisterSlot : public RegisterSlot 18 | { 19 | public: 20 | enum AvrFlagClasses 21 | { 22 | H = 0, 23 | S, 24 | V, 25 | N, 26 | Z, 27 | C, 28 | }; 29 | 30 | enum AvrRegisterClasses 31 | { 32 | ALL_REGISTERS, 33 | REGISTERS_16PLUS, 34 | REGISTER0, 35 | REGISTER1, 36 | REGISTER_EVEN, 37 | REGISTER_24PLUS_EVEN 38 | }; 39 | 40 | AvrRegisterSlot(AvrRegisterClasses rclass, bool _write=false, bool _read=true) : RegisterSlot(_write, _read) 41 | { 42 | setRegisterClassID(rclass); 43 | switch(rclass) 44 | { 45 | case ALL_REGISTERS: 46 | setValidArguments({0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31}); 47 | break; 48 | case REGISTERS_16PLUS: 49 | setValidArguments({16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31}); 50 | break; 51 | case REGISTER0: 52 | setValidArguments({0}); 53 | break; 54 | case REGISTER1: 55 | setValidArguments({1}); 56 | break; 57 | case REGISTER_EVEN: 58 | setValidArguments({0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30}); 59 | break; 60 | case REGISTER_24PLUS_EVEN: 61 | setValidArguments({24,26,28,30}); 62 | break; 63 | default: 64 | assert(!"Undefined register class"); 65 | } 66 | } 67 | }; 68 | 69 | class AvrConstantSlot: public ConstantSlot 70 | { 71 | public: 72 | AvrConstantSlot(std::vector> ranges_) : 73 | ConstantSlot(ranges_) {} 74 | }; 75 | 76 | 77 | // 32 registers and 6 flags 78 | class AvrMachine : public TargetMachineWithFlags 79 | { 80 | public: 81 | std::string toString() 82 | { 83 | std::string s; 84 | 85 | for(int i = 0; i < 32; ++i) 86 | { 87 | s += "\t"; 88 | s += "r" + std::to_string(i) + " = " + std::to_string(registers[i]) + " "; 89 | if(i % 4 == 3) 90 | s += "\n"; 91 | } 92 | 93 | return s; 94 | } 95 | 96 | std::vector> getInstructionFactories() 97 | { 98 | std::vector> factories; 99 | 100 | factories = Avr_getAutogeneratedInstructionFactories(); 101 | 102 | return factories; 103 | } 104 | 105 | bool operator ==(AvrMachine &rhs) 106 | { 107 | for(int i = 0; i < 32; ++i) 108 | { 109 | if(registers[i] != rhs.registers[i]) 110 | return false; 111 | } 112 | return true; 113 | } 114 | 115 | typedef AvrRegisterSlot RegisterSlot; 116 | typedef AvrConstantSlot ConstantSlot; 117 | }; 118 | 119 | // Compute the carry bit, given the inputs and output 120 | inline void setFlagAdd(AvrMachine *mach, uint8_t result, uint8_t rA, uint8_t rB) 121 | { 122 | bool R7 = (result >> 7) & 1; 123 | bool rA7= (rA >> 7) & 1; 124 | bool rB7= (rB >> 7) & 1; 125 | 126 | bool c = ((rA7 && rB7) || (rA7 && !R7) || (rB7 && !R7)); 127 | bool v = (!R7 && rA7 && rB7) || (R7 && !rA7 && !rB7); 128 | 129 | mach->setFlagValue(AvrRegisterSlot::C, c); 130 | mach->setFlagValue(AvrRegisterSlot::V, v); 131 | 132 | bool n = (result & 0x80) != 0; 133 | mach->setFlagValue(AvrRegisterSlot::Z, result == 0); 134 | mach->setFlagValue(AvrRegisterSlot::N, n); 135 | mach->setFlagValue(AvrRegisterSlot::S, n ^ v); 136 | } 137 | 138 | inline void setFlagZ(AvrMachine *mach, uint8_t out) 139 | { 140 | mach->setFlagValue(AvrRegisterSlot::Z, out == 0); 141 | } 142 | 143 | // For 8-bit outputs 144 | inline void setFlagSVNZ(AvrMachine *mach, uint8_t out, uint8_t v) 145 | { 146 | uint8_t n = (out & 0x80) != 0; 147 | mach->setFlagValue(AvrRegisterSlot::V, v); 148 | mach->setFlagValue(AvrRegisterSlot::Z, out == 0); 149 | mach->setFlagValue(AvrRegisterSlot::N, n); 150 | mach->setFlagValue(AvrRegisterSlot::S, n ^ v); 151 | } 152 | 153 | 154 | #include "avr_gen.hpp" 155 | 156 | 157 | 158 | #endif 159 | -------------------------------------------------------------------------------- /src/frontends/avr.yml: -------------------------------------------------------------------------------- 1 | defaults: 2 | operands: 3 | - type: "RegisterSlot" 4 | modifier: "rw" 5 | class: "ALL_REGISTERS" 6 | machine: 7 | register_slot_type: "AvrRegisterSlot" 8 | register_class_type: "AvrRegisterSlot::AvrRegisterClasses" 9 | constant_slot_type: "AvrConstantSlot" 10 | machine_type_name: "AvrMachine" 11 | class_prefix: "Avr_" 12 | register_type: "uint8_t" 13 | instructions: 14 | add: 15 | operands: 16 | - modifier: "rw" 17 | - modifier: "r" 18 | implementation: | 19 | uint8_t result = rA + rB; 20 | setFlagAdd(mach, result, rA, rB); 21 | rA = result; 22 | print_name: "add" 23 | format: "add {}, {}" 24 | adc: 25 | operands: 26 | - modifier: "rw" 27 | - modifier: "r" 28 | implementation: | 29 | bool c_flag = mach->getFlagValue(AvrRegisterSlot::C); 30 | uint8_t result = rA + rB + c_flag; 31 | setFlagAdd(mach, result, rA, rB); 32 | rA = result; 33 | print_name: "adc" 34 | format: "adc {}, {}" 35 | sub: 36 | operands: 37 | - modifier: "rw" 38 | - modifier: "r" 39 | implementation: | 40 | rA = rA - rB; 41 | print_name: "sub" 42 | format: "sub {}, {}" 43 | eor: 44 | operands: 45 | - modifier: "rw" 46 | - modifier: "r" 47 | implementation: | 48 | rA = rA ^ rB; 49 | print_name: "eor" 50 | format: "eor {}, {}" 51 | and: 52 | operands: 53 | - modifier: "rw" 54 | - modifier: "r" 55 | implementation: | 56 | rA = rA & rB; 57 | setFlagSVNZ(mach, rA, 0); 58 | print_name: "and" 59 | format: "and {}, {}" 60 | mul: 61 | operands: 62 | - modifier: "r" 63 | - modifier: "r" 64 | - modifier: "w" 65 | class: "REGISTER0" 66 | - modifier: "w" 67 | class: "REGISTER1" 68 | implementation: | 69 | rC = (rA * rB) & 0xFF; 70 | rD = (rA * rB) >> 8; 71 | mach->setFlagValue(AvrRegisterSlot::C, (rD & 0x80) != 0); 72 | mach->setFlagValue(AvrRegisterSlot::Z, rC == 0 && rD == 0); 73 | print_name: "mul" 74 | format: "mul {}, {}" 75 | inc: 76 | operands: 77 | - modifier: "rw" 78 | implementation: | 79 | setFlagSVNZ(mach, rA + 1, rA == 0x7F); 80 | rA = rA + 1; 81 | print_name: "inc" 82 | format: "inc {}" 83 | dec: 84 | operands: 85 | - modifier: "rw" 86 | implementation: | 87 | setFlagSVNZ(mach, rA - 1, rA == 0x80); 88 | rA = rA - 1; 89 | print_name: "dec" 90 | format: "dec {}" 91 | swap: 92 | operands: 93 | - modifier: "rw" 94 | implementation: | 95 | rA = (rA >> 4) | ((rA << 4) & 0xFF); 96 | print_name: "swap" 97 | format: "swap {}" 98 | ldi: 99 | operands: 100 | - type: "RegisterSlot" 101 | modifier: "w" 102 | class: "REGISTERS_16PLUS" 103 | - type: "ConstantSlot" 104 | ranges: 105 | - lower: 0 106 | upper: 255 107 | implementation: | 108 | rA = cB; 109 | print_name: "ldi" 110 | format: "ldi {}, {}" 111 | movw: 112 | operands: 113 | - type: "RegisterSlot" 114 | modifier: "w" 115 | class: "REGISTER_EVEN" 116 | - type: "RegisterSlot" 117 | modifier: "r" 118 | class: "REGISTER_EVEN" 119 | implementation: | 120 | uint8_t rB_p = mach->getRegisterValue(slots[1]->getValue()+1); 121 | 122 | rA = rB; 123 | mach->setRegisterValue(slots[0]->getValue()+1, rB_p); 124 | print_name: "movw" 125 | format: "movw {}, {}" 126 | adiw: 127 | operands: 128 | - type: "RegisterSlot" 129 | modifier: "rw" 130 | class: "REGISTER_24PLUS_EVEN" 131 | - type: "ConstantSlot" 132 | ranges: 133 | - lower: 0 134 | upper: 63 135 | implementation: | 136 | uint8_t rA_p = mach->getRegisterValue(slots[0]->getValue()+1); 137 | 138 | uint16_t tmp = (rA_p << 8) | rA; 139 | 140 | tmp += cB; 141 | 142 | rA = tmp & 0xFF; 143 | mach->setRegisterValue(slots[0]->getValue()+1, (tmp >> 8)&0xFF); 144 | print_name: "adiw" 145 | format: "adiw {}, {}" 146 | -------------------------------------------------------------------------------- /src/generate.py: -------------------------------------------------------------------------------- 1 | """Generate the instruction classes 2 | 3 | Usage: 4 | ./generate.py INPUTFILE OUTPUTFILE 5 | """ 6 | 7 | from docopt import docopt 8 | import yaml 9 | from copy import deepcopy 10 | import collections 11 | import string 12 | 13 | arguments = docopt(__doc__) 14 | 15 | template = """ 16 | class {class_prefix}{insn_name} : public Instruction 17 | {{ 18 | public: 19 | unsigned execute(TargetMachineBase *_mach, Slot** slots) override 20 | {{ 21 | // TODO assert enough slots 22 | // TODO assert slot types are RegisterSlots 23 | 24 | {machine_type_name} *mach = static_cast<{machine_type_name}*>(_mach); 25 | {reg_read} 26 | 27 | {code} 28 | 29 | {reg_write} 30 | 31 | return {n_slots}; 32 | }} 33 | 34 | // Return the number and types of register slots required 35 | // which ones are read and written 36 | std::vector getSlots() override 37 | {{ 38 | return {{ {slots} }}; 39 | }} 40 | 41 | unsigned getNumberOfSlots() override 42 | {{ 43 | return {n_slots}; 44 | }} 45 | 46 | std::string toString() override 47 | {{ 48 | return fmt::format("{format}" {print_slotlist_str}); 49 | }} 50 | 51 | std::string toString(Slot** slots) override 52 | {{ 53 | return fmt::format("{format}" {print_slotlist}); 54 | }} 55 | 56 | std::string getName() override 57 | {{ 58 | return "{print_name}"; 59 | }} 60 | 61 | bool parse(std::string input, std::vector &slotlist) override 62 | {{ 63 | auto slots = getSlots(); 64 | 65 | bool success = cppinput::input(input, "{format}" {print_slotlist}); 66 | 67 | if(success) 68 | {{ 69 | slotlist.insert(slotlist.end(), slots.begin(), slots.end()); 70 | }} 71 | else 72 | {{ 73 | for(auto slot: slots) 74 | delete slot; 75 | }} 76 | 77 | return success; 78 | }} 79 | 80 | }}; 81 | """ 82 | 83 | factory_template = """ 84 | std::vector> {class_prefix}getAutogeneratedInstructionFactories() 85 | {{ 86 | std::vector> factories; 87 | 88 | {factories} 89 | 90 | return factories; 91 | }} 92 | 93 | """ 94 | 95 | factory_lambda_template = """ 96 | factories.push_back([] {{ return new {class_prefix}{insn_name}();}}); 97 | """ 98 | 99 | # Recursively merge dictionaries, giving priority to params. If a list 100 | # is encountered, we expect that there will be one entry, and that will 101 | # provide default values for every item in that list. 102 | def apply_defaults(params, defaults): 103 | try: 104 | if params is None: 105 | params = defaults 106 | if type(params) in [str, unicode, int, long, float]: 107 | pass 108 | elif isinstance(params, list): 109 | # If there is a default entry, the list must be length one 110 | # and then we apply those defaults to the parameters 111 | if isinstance(defaults, list): 112 | if len(defaults) > 1: 113 | raise ValueError("More than one defaults in list") 114 | for item in params: 115 | apply_defaults(item, defaults[0]) 116 | else: 117 | pass 118 | elif isinstance(params, dict): 119 | if isinstance(defaults, dict): 120 | for key in defaults: 121 | if key in params: 122 | params[key] = apply_defaults(params[key], defaults[key]) 123 | else: 124 | params[key] = defaults[key] 125 | else: 126 | raise ValueError("Params dictionary met with non-dictionary default: {}, {}".format(params, defaults)) 127 | else: 128 | raise RuntimeException("Unable to apply defaults to {} (from {})".format(params, defaults)) 129 | except TypeError, e: 130 | raise TypeError("TypeError: Unable to apply defaults to {} (from {})".format(params, defaults)) 131 | return params 132 | 133 | with open(arguments["INPUTFILE"]) as f: 134 | obj = yaml.load(f) 135 | 136 | machine = obj["machine"] 137 | register_type = machine["register_type"] 138 | register_slot_type = machine["register_slot_type"] 139 | register_class_type = machine["register_class_type"] 140 | constant_slot_type = machine["constant_slot_type"] 141 | class_prefix = machine["class_prefix"] 142 | machine_type_name = machine["machine_type_name"] 143 | 144 | with open(arguments["OUTPUTFILE"], "w") as fout: 145 | factories = [] 146 | for insn_name, params_ in obj["instructions"].items(): 147 | defaults = deepcopy(obj["defaults"]) 148 | params = apply_defaults(params_, defaults) 149 | 150 | code = params['implementation'] 151 | operands = params['operands'] 152 | format = params['format'] 153 | 154 | print_name = params['print_name'] 155 | reg_read = "" 156 | reg_write = "" 157 | slots = [] 158 | for i, op in enumerate(operands): 159 | if op["type"] == "RegisterSlot": 160 | if "r" in op["modifier"]: 161 | reg_read += "{} r{} = mach->getRegister(slots[{}]);\n".format(register_type, chr(65+i), i) 162 | else: 163 | reg_read += "{} r{} = 0;\n".format(register_type, chr(65+i)) 164 | 165 | if "w" in op["modifier"]: 166 | reg_write += "mach->setRegister(slots[{}], r{});\n".format(i, chr(65+i)) 167 | 168 | slots.append("new {}({}::{}, {}, {})".format( 169 | register_slot_type, 170 | register_class_type, 171 | op["class"], 172 | "true" if "w" in op["modifier"] else "false", 173 | "true" if "r" in op["modifier"] else "false")) 174 | elif op["type"] == "ConstantSlot": 175 | ranges = [] 176 | for r in op["ranges"]: 177 | ranges.append("{{{}, {}}}".format(r["lower"], r["upper"])) 178 | 179 | reg_read += "{} c{} = slots[{}]->getValue();\n".format(register_type, chr(65+i), i) 180 | slots.append("new {}({{{}}})".format(constant_slot_type, ", ".join(ranges))) 181 | 182 | slots = ", ".join(slots) 183 | n_slots = len(operands) 184 | 185 | placeholders = [k for k in string.Formatter().parse(format) if k[1] is not None] 186 | n_placeholders = len(placeholders) 187 | 188 | print_slotlist = "".join([", *slots[{}]".format(i) for i in range(n_placeholders)]) 189 | print_slotlist_str = "".join([", \"S{}\"".format(i) for i in range(n_placeholders)]) 190 | 191 | s = template.format(**locals()) 192 | 193 | fout.write(s) 194 | 195 | # Make generator lambdas for factories 196 | factories.append(factory_lambda_template.format(**locals())) 197 | fout.write(factory_template.format(class_prefix=class_prefix, factories="".join(factories))) 198 | 199 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "frontends/avr.hpp" 6 | #include "algorithms/canonicalIterator.hpp" 7 | #include "algorithms/constantIterator.hpp" 8 | #include "algorithms/bruteforce.hpp" 9 | #include "algorithms/test.hpp" 10 | #include "utility.hpp" 11 | 12 | using namespace std; 13 | 14 | typedef AvrMachine MachineType; 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | // TODO: options 19 | 20 | std::string instruction_str = 21 | "add r0, r0\n" 22 | "add r0, r0\n" 23 | "add r0, r0\n" 24 | "add r0, r0\n" 25 | "add r0, r0"; 26 | 27 | 28 | MachineType mach, mach_expected, mach_initial; 29 | 30 | // Compute a test state - for quick discarding of invalid sequences. 31 | mach_expected.initialiseRandom(); 32 | mach_initial = mach_expected; 33 | 34 | // Get a list of functions which will construct an instruction 35 | auto insn_factories = mach.getInstructionFactories(); 36 | 37 | vector current_factories; 38 | 39 | // The number of instructions should eventually be parameterised 40 | current_factories.push_back(insn_factories.begin()); 41 | current_factories.push_back(insn_factories.begin()); 42 | current_factories.push_back(insn_factories.begin()); 43 | current_factories.push_back(insn_factories.begin()); 44 | 45 | // Get a list of instructions and slots from the string 46 | vector goal_insns; 47 | vector goal_slots; 48 | 49 | parseInstructionList(instruction_str, insn_factories, goal_insns, goal_slots); 50 | 51 | // Create a quick test state 52 | executeSequence(goal_insns, goal_slots, mach_expected); 53 | 54 | cout << "Goal sequence:\n"; 55 | cout << print(goal_insns, goal_slots) << endl; 56 | 57 | 58 | do { 59 | vector insns; 60 | vector slots; 61 | 62 | // Create the instructions, as per the current iterator 63 | // Get a list of all of the slots in the instruction list 64 | for(auto &factory: current_factories) 65 | { 66 | Instruction *insn = (*factory)(); 67 | 68 | insns.push_back(insn); 69 | 70 | auto s1 = insn->getSlots(); 71 | slots.insert(slots.end(), s1.begin(), s1.end()); 72 | } 73 | 74 | 75 | canonicalIteratorBasic c_iter(slots, 0); 76 | 77 | constantIterator cons_iter(slots); 78 | cons_iter.setLossy(true); 79 | 80 | // Bruteforce over the possible constants, and canonically iterate 81 | // over the register slots. 82 | do 83 | { 84 | do 85 | { 86 | // Perform an equivalence test, and if it succeeds, run 87 | // multiple tests to work out if the sequence is likely to be 88 | // correct. 89 | if(testEquivalence(insns, slots, mach_initial, mach_expected)) 90 | { 91 | bool correct = testEquivalenceMultiple(insns, slots, goal_insns, goal_slots); 92 | 93 | if(correct) 94 | { 95 | auto mapping = canonicalMapping(slots); 96 | 97 | if(mapping.second) 98 | { 99 | cout << "Found" << endl; 100 | cout << print(insns, slots) << endl; 101 | } 102 | } 103 | } 104 | } while(c_iter.next()); 105 | } while(cons_iter.next()); 106 | 107 | // Free the instructions and slots 108 | for(auto slot: slots) 109 | delete slot; 110 | for(auto insn: insns) 111 | delete insn; 112 | 113 | } while(bruteforceIterate(insn_factories, current_factories)); 114 | 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /src/main_parallel.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include "parallel/mpi.hpp" 7 | 8 | #include "frontends/avr.hpp" 9 | #include "algorithms/canonicalIterator.hpp" 10 | #include "algorithms/constantIterator.hpp" 11 | #include "algorithms/bruteforce.hpp" 12 | #include "algorithms/test.hpp" 13 | #include "utility.hpp" 14 | 15 | using namespace std; 16 | 17 | typedef AvrMachine MachineType; 18 | // typedef x86_64_Machine MachineType; 19 | 20 | int main(int argc, char *argv[]) 21 | { 22 | // TODO: options 23 | 24 | MPI_Init(NULL, NULL); 25 | 26 | std::string instruction_str = 27 | "add r0, r0\n" 28 | "add r0, r0\n" 29 | "add r0, r0\n" 30 | "add r0, r0\n" 31 | "add r0, r0"; 32 | 33 | MachineType mach, mach_expected, mach_initial; 34 | 35 | // Compute a test state - for quick discarding of invalid sequences. 36 | mach_expected.initialiseRandom(); 37 | mach_initial = mach_expected; 38 | 39 | // Get a list of functions which will construct an instruction 40 | auto insn_factories = mach.getInstructionFactories(); 41 | 42 | vector current_factories; 43 | 44 | // The number of instructions should eventually be parameterised 45 | current_factories.push_back(insn_factories.begin()); 46 | current_factories.push_back(insn_factories.begin()); 47 | current_factories.push_back(insn_factories.begin()); 48 | current_factories.push_back(insn_factories.begin()); 49 | 50 | int world_rank; 51 | MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); 52 | 53 | if(world_rank == 0) 54 | { 55 | vector factory_ids; 56 | 57 | for(unsigned i = 0; i < insn_factories.size(); ++i) 58 | factory_ids.push_back(i); 59 | 60 | vector> factory_lists; 61 | vector insn_sizes; 62 | 63 | cout << "MASTER "<getNumberOfSlots()); 74 | delete insn; 75 | } 76 | 77 | distributeTasks(factory_lists, 78 | [&](std::vector::iterator> &iters) 79 | { 80 | int i = 1; 81 | 82 | for(auto &it: iters) 83 | i *= insn_sizes[*it]+1; 84 | // cout << i << endl; 85 | return -i; 86 | } 87 | ); 88 | 89 | MPI_Finalize(); 90 | return 0; 91 | } 92 | 93 | cout << "SLAVE " << world_rank << endl; 94 | 95 | // Get a list of instructions and slots from the string 96 | vector goal_insns; 97 | vector goal_slots; 98 | 99 | parseInstructionList(instruction_str, insn_factories, goal_insns, goal_slots); 100 | 101 | // Create a quick test state 102 | executeSequence(goal_insns, goal_slots, mach_expected); 103 | 104 | cout << "Goal sequence:\n"; 105 | cout << print(goal_insns, goal_slots) << endl; 106 | 107 | 108 | vector insn_ids; 109 | 110 | while(getWork(insn_ids)) { 111 | vector insns; 112 | 113 | // Create the instructions, as per the current iterator 114 | for(unsigned i = 0; i < insn_ids.size(); ++i) 115 | insns.push_back(insn_factories[insn_ids[i]]()); 116 | 117 | vector slots; 118 | 119 | // Get a list of all of the slots in the instruction list 120 | for(auto insn: insns) 121 | { 122 | auto s1 = insn->getSlots(); 123 | slots.insert(slots.end(), s1.begin(), s1.end()); 124 | } 125 | 126 | canonicalIteratorBasic c_iter(slots, 0); 127 | 128 | constantIterator cons_iter(slots); 129 | cons_iter.setLossy(true); 130 | 131 | // Bruteforce over the possible constants, and canonically iterate 132 | // over the register slots. 133 | do 134 | { 135 | do 136 | { 137 | // Perform an equivalence test, and if it succeeds, run 138 | // multiple tests to work out if the sequence is likely to be 139 | // correct. 140 | if(testEquivalence(insns, slots, mach_initial, mach_expected)) 141 | { 142 | bool correct = testEquivalenceMultiple(insns, slots, goal_insns, goal_slots); 143 | 144 | if(correct) 145 | { 146 | auto mapping = canonicalMapping(slots); 147 | 148 | if(mapping.second) 149 | { 150 | cout << "Found" << endl; 151 | cout << print(insns, slots) << endl; 152 | } 153 | } 154 | } 155 | } while(c_iter.next()); 156 | } while(cons_iter.next()); 157 | 158 | // Free the instructions and slots 159 | for(auto slot: slots) 160 | delete slot; 161 | for(auto insn: insns) 162 | delete insn; 163 | 164 | } 165 | 166 | MPI_Finalize(); 167 | 168 | return 0; 169 | } 170 | -------------------------------------------------------------------------------- /src/parallel/mpi.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __MPI_HPP__ 2 | #define __MPI_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | #include "../algorithms/bruteforce.hpp" 8 | #include "../algorithms/bruteforceByCost.hpp" 9 | 10 | #define REQ_TASK 1 11 | #define TASK 2 12 | 13 | #define FINISHED 3 14 | 15 | void distributeTasks(std::vector> &values, 16 | std::function::iterator> &)> costFn) 17 | { 18 | char buf[1]; 19 | MPI_Status status; 20 | uint64_t total_size = 1; 21 | uint64_t current_size=0; 22 | 23 | std::vector::iterator> iterators; 24 | std::vector iters_int(values.size()); 25 | 26 | for(auto &v: values) 27 | { 28 | iterators.push_back(v.begin()); 29 | total_size *= v.size(); 30 | } 31 | 32 | bruteforceByCost> bfbc(values, iterators, costFn); 33 | 34 | do { 35 | MPI_Recv(buf, 1, MPI_CHAR, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); 36 | 37 | for(unsigned i = 0; i < iterators.size(); ++i) 38 | { 39 | std::cout << *iterators[i] << " "; 40 | iters_int[i] = *iterators[i]; 41 | } 42 | std::cout << "\n"; 43 | 44 | MPI_Send(&iters_int[0], iters_int.size(), MPI_INT, status.MPI_SOURCE, 45 | TASK, MPI_COMM_WORLD); 46 | 47 | current_size++; 48 | std::cout << double(current_size) / double(total_size) *100.<< "%" << std::endl; 49 | } while(bfbc.next()); 50 | 51 | // TODO wait for children to terminate 52 | int world_size; 53 | MPI_Comm_size(MPI_COMM_WORLD, &world_size); 54 | 55 | for(unsigned i = 1; i < world_size; ++i) 56 | MPI_Send(&buf, 1, MPI_CHAR, i, 57 | FINISHED, MPI_COMM_WORLD); 58 | } 59 | 60 | void distributeTasks(std::vector> &values) 61 | { 62 | distributeTasks(values, 63 | [](std::vector::iterator> &iters) 64 | { 65 | int i = 0; 66 | 67 | for(auto &it: iters) 68 | i += *it; 69 | return -i; 70 | }); 71 | } 72 | 73 | bool getWork(std::vector &data) 74 | { 75 | char buf[1] = {0}; 76 | MPI_Status status; 77 | int count; 78 | 79 | MPI_Send(buf, 1, MPI_CHAR, 0, REQ_TASK, MPI_COMM_WORLD); 80 | 81 | MPI_Probe(0, MPI_ANY_TAG, MPI_COMM_WORLD, &status); 82 | 83 | if(status.MPI_TAG == FINISHED) 84 | { 85 | return false; 86 | } 87 | 88 | MPI_Get_count(&status, MPI_INT, &count); 89 | 90 | data.resize(count); 91 | 92 | MPI_Recv(&data[0], count, MPI_INT, 0, TASK, MPI_COMM_WORLD, &status); 93 | 94 | return true; 95 | } 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /src/slots.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __SLOTS_HPP__ 2 | #define __SLOTS_HPP__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /*! \class Slot 10 | 11 | The slot class is the basis of all the parameters in the instruction 12 | which can be iterated over by a superoptimizer. For example, the class 13 | is subclassed to represent registers and constants. 14 | */ 15 | 16 | class Slot 17 | { 18 | public: 19 | virtual ~Slot() {} 20 | 21 | /*! Get the value stored by the slot. 22 | 23 | @return The value stored by the slot. 24 | */ 25 | virtual uint64_t getValue() const 26 | { 27 | return value; 28 | } 29 | 30 | /*! Set the value stored in the slot. 31 | 32 | @param val Set the value stored to val. 33 | */ 34 | virtual void setValue(uint64_t val) 35 | { 36 | value = val; 37 | } 38 | 39 | /*! Reset the value in the slot. This is subclassed, to reset the value, 40 | since it doesn't necessarily make sense to reset the value sometimes. 41 | */ 42 | virtual void reset() 43 | { 44 | 45 | } 46 | 47 | /*! Stream operator to display the slot's value on the specified stream. 48 | 49 | @param os The stream to output to. 50 | @param d The slot whose value to output. 51 | @return The stream. 52 | */ 53 | friend std::ostream &operator<<(std::ostream &os, const Slot &d) 54 | { 55 | return os << d.toString(); 56 | } 57 | 58 | /*! Stream operator to display the slot's value on the specified stream. 59 | This is mostly a convenience function, since Slots are often refered 60 | to via pointers. 61 | 62 | @param os The stream to output to. 63 | @param d The slot whose value to output. 64 | @return The stream. 65 | */ 66 | friend std::ostream &operator<<(std::ostream &os, const Slot *d) 67 | { 68 | return os << d->toString(); 69 | } 70 | 71 | /*! Stream operator to input a value into the slot. 72 | 73 | This is a forwarding function, which calls the virtual function input. 74 | This ensures that the proper parsing of the slot can be performed 75 | (e.g. recognising registers or constants). 76 | 77 | @param in The input stream. 78 | @param d The slot to input into. 79 | @return The stream. 80 | */ 81 | friend std::istream &operator>>(std::istream &in, Slot &d) 82 | { 83 | return d.input(in); 84 | } 85 | 86 | protected: 87 | uint64_t value; 88 | 89 | /*! A conversion method, since the friend stream operators cannot be 90 | virtual. The method converts the slot's value to a string which 91 | can be displayed. 92 | 93 | @return The printable string of the slot's value. 94 | */ 95 | virtual std::string toString() const 96 | { 97 | return std::to_string(getValue()); 98 | } 99 | 100 | /*! Input method. 101 | 102 | This inputs a value from the input stream into the slot's value. This 103 | function will be overridden if a different input format is required by 104 | subclasses. 105 | 106 | @param in The input stream. 107 | @return The input stream. 108 | */ 109 | virtual std::istream &input(std::istream &in) 110 | { 111 | unsigned v; 112 | 113 | in >> v; 114 | 115 | if(!in.fail()) 116 | setValue(v); 117 | 118 | return in; 119 | } 120 | }; 121 | 122 | /*! \class RegisterSlot 123 | 124 | The RegisterSlot class contains information about a slot which can accept 125 | different registers. Information, such as whether the register is read, 126 | written, and its valid arguments are stored. 127 | */ 128 | 129 | class RegisterSlot : public Slot 130 | { 131 | public: 132 | /*! Initialise the RegisterSlot, with information about the class of 133 | values that can be stored, and whether the slot is a writable 134 | register, readable register or both. The _validArguments parameter 135 | should be sorted for the canonical form iterators to work properly. 136 | 137 | @param _write Specify whether the register slot represents a 138 | register which is written to by an instruction. 139 | @param _read Specify whether the register slot represents 140 | a register which is read by an instruction. 141 | @param _validArguments 142 | A list of the possible values the register slot 143 | will accept. 144 | @param value An value to initialise the slot to. 145 | */ 146 | RegisterSlot(bool _write=false, bool _read=true, 147 | std::vector _validArguments={}, unsigned value=0, int _classid=-1) 148 | { 149 | read = _read; 150 | write = _write; 151 | validArguments = _validArguments; 152 | classid = _classid; 153 | std::sort(validArguments.begin(), validArguments.end()); 154 | setValue(value); 155 | } 156 | 157 | /*! Get the list of registers that the slot will accept. 158 | 159 | @return The list of accepted register names. 160 | */ 161 | std::vector getValidArguments() 162 | { 163 | return validArguments; 164 | } 165 | 166 | /*! Set the list of acceptable registers for this slot. 167 | 168 | @param validArguments_ The values which this RegisterSlot can take. 169 | */ 170 | void setValidArguments(std::vector validArguments_) 171 | { 172 | validArguments = validArguments_; 173 | std::sort(validArguments.begin(), validArguments.end()); 174 | } 175 | 176 | /*! Reset the value of the Slot to the first in the set of valid 177 | arguments, if one has been set. Otherwise, do not reset the value. 178 | */ 179 | virtual void reset() override 180 | { 181 | if(validArguments.size() > 0) 182 | setValue(validArguments[0]); 183 | } 184 | 185 | /*! Get the ID of the register class associated with this register slot 186 | 187 | @return The class ID of the register slot. 188 | */ 189 | int getRegisterClassID() 190 | { 191 | return classid; 192 | } 193 | 194 | /*! Set the ID of the register class associated with this register slot 195 | 196 | @param classid The class ID of the register slot. 197 | */ 198 | void setRegisterClassID(int classid) 199 | { 200 | this->classid = classid; 201 | } 202 | 203 | /*! Check whether the slot writes to its register 204 | 205 | @return True if the register refered to by the slot gets written. 206 | */ 207 | bool isWriteSlot() 208 | { 209 | return write; 210 | } 211 | 212 | /*! Check whether the slot reads its register 213 | 214 | @return True if the register refered to by the slot is read. 215 | */ 216 | bool isReadSlot() 217 | { 218 | return read; 219 | } 220 | 221 | private: 222 | bool read, write; 223 | int classid; 224 | std::vector validArguments; 225 | 226 | protected: 227 | /*! Format the register for output. 228 | 229 | By default the format just prepends 'r' to the number stored in the 230 | slot. 231 | 232 | @return A string representing the register. 233 | */ 234 | virtual std::string toString() const override 235 | { 236 | return "r" + std::to_string(getValue()); 237 | } 238 | 239 | /*! Parse a register and store its value. 240 | 241 | The format expected is rX, where X is the register number. If this 242 | could not be matched, the fail bit of the stream is set. 243 | 244 | @param in The input stream. 245 | @return The input streamm. 246 | */ 247 | virtual std::istream &input(std::istream &in) override 248 | { 249 | unsigned v; 250 | char r; 251 | 252 | in >> r >> v; 253 | 254 | if(!in.fail() && r != 'r') 255 | in.setstate(std::ios::failbit); 256 | 257 | if(!in.fail()) 258 | setValue(v); 259 | 260 | return in; 261 | } 262 | }; 263 | 264 | /*! \class ConstantSlot 265 | 266 | The constant slot holds a constant value that may be given to an 267 | instruction. The constant slot accepts a number of ranges, each which 268 | describe which constants may be set for the instruction. While most 269 | instructions just accept a single range of constants, this allows the 270 | number of constants considered to be restricted arbitrarily, since 271 | iterating through every possible constant vastly increases the search 272 | space. 273 | 274 | The constant slot has a 'lossy' mode, where only certain constants will be 275 | iterated. This is enabled by the iteratorSkip function. The constant 276 | enabled by setting the lossy setting include all in the range 0 to 16, 2^n 277 | for all n, and 2^n - 1 for all n. 278 | 279 | TODO: Should the logic for lossy mode be moved into constantIterator 280 | instead? 281 | */ 282 | 283 | class ConstantSlot : public Slot 284 | { 285 | public: 286 | 287 | /*! Initialise the constant slot. 288 | 289 | The ranges of the constant slot are initialise here. Each range is 290 | inclusive, with the first number being the lowest and the second 291 | number being the highest (and last) number to assign to the constant 292 | slot. 293 | 294 | @param ranges_ A list of ranges for the constant slot. 295 | */ 296 | ConstantSlot(std::vector> ranges_) 297 | { 298 | // TODO: validate that the ranges are strictly ordered, i.e., they are 299 | // in order and non-overlapping. 300 | ranges = ranges_; 301 | current_range = 0; 302 | lossy = false; 303 | } 304 | 305 | /*! Reset the value of the slot. 306 | 307 | The value is the lower (i.e. first value in the first range), or the 308 | lowest value in this list of lossy values. 309 | */ 310 | virtual void reset() override 311 | { 312 | if(lossy) 313 | { 314 | current_range = 0; 315 | value = lossy_values[0]; 316 | } 317 | else 318 | { 319 | if(ranges.size() > 0) 320 | { 321 | value = ranges[0].first; 322 | current_range = 0; 323 | } 324 | } 325 | } 326 | 327 | /*! Set the slot value to the next constant value. 328 | 329 | If the last value has been reached, and the value wraps around, false 330 | is returned, otherwise true. 331 | 332 | If lossy mode is enabled, this function just increments current_range 333 | and uses this to index into the list of lossy values. Otherwise, it is 334 | determined whether the current value is with in a particular range. If 335 | the end of that range has been reached the next range is selected. 336 | 337 | @return True if there are still more value to iterate over. 338 | */ 339 | bool next() 340 | { 341 | assert(ranges.size() > 0); 342 | 343 | if(lossy) 344 | { 345 | // Iterate over the lossy values instead. 346 | current_range++; 347 | if(current_range >= lossy_values.size()) 348 | { 349 | current_range = 0; 350 | value = lossy_values[0]; 351 | return false; 352 | } 353 | else 354 | { 355 | value = lossy_values[current_range]; 356 | return true; 357 | } 358 | } 359 | else 360 | { 361 | // Find out whether we are at the end of our current range or not. 362 | if(value >= ranges[current_range].second) 363 | { 364 | current_range++; 365 | if(current_range >= ranges.size()) 366 | { 367 | current_range = 0; 368 | value = ranges[current_range].first; 369 | return false; 370 | } 371 | else 372 | { 373 | value = ranges[current_range].first; 374 | return true; 375 | } 376 | } 377 | else 378 | { 379 | value++; 380 | return true; 381 | } 382 | } 383 | } 384 | 385 | /*! Enable skipping of infrequently used constants. 386 | 387 | Some constants are used more frequently than others in programs. The 388 | constant enabled by setting the lossy setting include all in the range 389 | 0 to 16, 2^n for all n, and 2^n - 1 for all n. This function resets 390 | the current range. 391 | 392 | The lossy values are implemented by storing all the possible values in 393 | lossy_values, which is then iterated by next. 394 | 395 | @param lossy_ Whether to enable to lossy iteration of constants or 396 | not. 397 | */ 398 | void iteratorSkip(bool lossy_) 399 | { 400 | lossy = lossy_; 401 | 402 | // Reset the counter to 0, since we may change mode of operation. 403 | current_range = 0; 404 | 405 | // Precompute the lossy values and store them. 406 | lossy_values.clear(); 407 | 408 | if(!lossy) 409 | return; 410 | 411 | for(auto &p: ranges) 412 | { 413 | // Add all values under 16 to lossy_values, if they are in the 414 | // range. 415 | if(p.first < 16) 416 | { 417 | for(uint64_t i = p.first; i < 16 && i < p.second; ++i) 418 | lossy_values.push_back(i); 419 | } 420 | 421 | // Starting at 16, add all powers of two, and all powers of two 422 | // minus one to the list, as long as they appear in the current 423 | // range. 424 | uint64_t v = 16; 425 | for(unsigned i = 4; i < sizeof(uint64_t)*8; ++i, v <<= 1) 426 | { 427 | // 2^n 428 | if(v >= p.first && v <= p.second) 429 | { 430 | lossy_values.push_back(v); 431 | } 432 | // 2^n - 1 433 | if(v-1 >= p.first && v-1 <= p.second) 434 | { 435 | lossy_values.push_back(v-1); 436 | } 437 | } 438 | } 439 | } 440 | 441 | private: 442 | // Ranges are inclusive 443 | std::vector> ranges; 444 | 445 | bool lossy; 446 | std::vector lossy_values; 447 | 448 | // Current range is used to describe which range is begin picked from if 449 | // we are not iterating lossily, otherwise it is the index of the current 450 | // value in the lossy_values list. 451 | unsigned current_range; 452 | 453 | }; 454 | 455 | #endif 456 | -------------------------------------------------------------------------------- /src/utility.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "frontend.hpp" 7 | #include "utility.hpp" 8 | 9 | using namespace std; 10 | 11 | Combinations::Combinations(unsigned size_, unsigned n_) 12 | { 13 | // TODO check values.size() <= 63 14 | n = n_; 15 | size = size_; 16 | current = (1 << n) - 1; 17 | max = (current << (size - n)); 18 | } 19 | 20 | // TODO: should we return the actual values here, rather than the index of 21 | // the value? 22 | void Combinations::getSelection(std::vector &sel) 23 | { 24 | uint64_t val = current; 25 | unsigned current_idx = 0; 26 | 27 | sel.resize(n); 28 | 29 | // Iterate through each bit in val, and if set, add the current value to 30 | // the list. 31 | for(unsigned i = 0; i < size; ++i, val >>= 1) 32 | { 33 | if(val & 1) 34 | sel[current_idx++] = i; 35 | } 36 | } 37 | 38 | bool Combinations::next() 39 | { 40 | uint64_t smallest, ripple, ones, x = current; 41 | 42 | // snoob function. Next unsigned integer with the same number of one 43 | // bits set. 44 | smallest = x & -x; 45 | ripple = x + smallest; 46 | ones = x ^ ripple; 47 | ones = (ones >> 2) /smallest; 48 | 49 | current = ripple | ones; 50 | // End snoob function. 51 | 52 | // Check if we have reached the end, and if so, reset current to its first 53 | // value. 54 | if(current > max || (max == 1 && current == 1)) 55 | { 56 | current = (1< &insns, 64 | vector &slots) 65 | { 66 | auto slot = &slots[0]; 67 | stringstream ss; 68 | 69 | for(auto insn: insns) 70 | { 71 | ss << insn->toString(slot) << endl; 72 | slot += insn->getNumberOfSlots(); 73 | } 74 | ss << endl; 75 | 76 | return ss.str(); 77 | } 78 | 79 | 80 | pair> parseInstruction(string input, vector> factories) 81 | { 82 | vector insns; 83 | vector slots; 84 | 85 | for(auto &factory: factories) 86 | insns.push_back(factory()); 87 | 88 | // Iterate through all the instructions created, and pick the first one 89 | // that accepts the string we are given. 90 | for(unsigned int i = 0; i < insns.size(); ++i) 91 | { 92 | bool success = insns[i]->parse(input, slots); 93 | 94 | if(success) 95 | { 96 | Instruction *insn = factories[i](); 97 | 98 | return make_pair(insn, slots); 99 | } 100 | } 101 | 102 | // TODO deallocate insns 103 | 104 | return make_pair(nullptr, vector()); 105 | } 106 | 107 | bool parseInstructionList(string input, vector> factories, 108 | vector &insns, vector &slots) 109 | { 110 | vector lines; 111 | 112 | // Split the input string on newlines 113 | boost::split(lines, input, boost::is_any_of("\n")); 114 | 115 | // Attempt to match each line as an instruction 116 | for(auto line: lines) 117 | { 118 | auto insn_data = parseInstruction(line, factories); 119 | 120 | if(insn_data.first == nullptr) 121 | { 122 | cout << "Could not recognise line of input:\n\t" << line << endl; 123 | return false; 124 | } 125 | 126 | // Create a list of slots 127 | auto insn_slots = insn_data.second; 128 | slots.insert(slots.end(), insn_slots.begin(), insn_slots.end()); 129 | 130 | insns.push_back(insn_data.first); 131 | } 132 | 133 | return true; 134 | } 135 | -------------------------------------------------------------------------------- /src/utility.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __UTILITY_H__ 2 | #define __UTILITY_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /*! \class Combinations 10 | 11 | Construction a list of N combinations from SIZE possibilities. This class 12 | iterates over all possible combinations, returning a list of length N, 13 | with the selections. It is intended for these selections to be indices 14 | into another list with objects to be selected. 15 | 16 | Note: if SIZE is greater than 63 this will break. 17 | 18 | 19 | Example: 20 | Combinations c(4,2); 21 | 22 | c.getSelection(); // {0, 1} 23 | c.next(); 24 | c.getSelection(); // {0, 2} 25 | c.next(); 26 | c.getSelection(); // {0, 3} 27 | c.next(); 28 | c.getSelection(); // {1, 2} 29 | ... 30 | c.next(); 31 | c.getSelection(); // {2,3} 32 | c.next(); // Return false 33 | c.getSelection(); // {0,1} 34 | 35 | TODO: perhaps getSelection should be renamed to getIndices. 36 | */ 37 | class Combinations 38 | { 39 | public: 40 | /*! Initialise the combinations generator. 41 | 42 | This initialise the internal variables, such that an immediate call to 43 | getSelection returns the correct values (i.e. before calling next); 44 | 45 | @param size_ The number of objects to choose combinations from. 46 | @param n_ The number of objects to choose. 47 | 48 | */ 49 | Combinations(unsigned size_, unsigned n_); 50 | 51 | /*! Return the list of current combinations. 52 | 53 | This returns a sorted list of the current combination chosen. The 54 | values are returned in the variable passed in the arguments list 55 | (reference) to avoid the recreation of the object, since it is 56 | expected that this function may be in a hot loop. 57 | 58 | @param sel The list in which to put the current combinations. 59 | */ 60 | void getSelection(std::vector &sel); 61 | 62 | /*! Advance to the next combination. 63 | 64 | This function computes the next combination from the current one, 65 | returning true if the entire sequence is finished and has wrapped 66 | around. 67 | 68 | @return True if all combinations have been iterated. 69 | */ 70 | bool next(); 71 | 72 | private: 73 | uint64_t current, max; 74 | unsigned n, size; 75 | }; 76 | 77 | class Instruction; 78 | class Slot; 79 | 80 | /*! Format the instruction sequence into a string. 81 | 82 | This function takes a list of instruction, and their corresponding slots, 83 | formatting it into a string. Each instruction is separated by a newline, 84 | and otherwise formatted as specified by the instruction. 85 | 86 | E.g. 87 | mov r0, r1 88 | add r1, r2 89 | 90 | @param insns The instruction to format. 91 | @param slots The slots corresponding to the instructions. 92 | @return A string representing the instructions 93 | */ 94 | std::string print(const std::vector &insns, 95 | std::vector &slots); 96 | 97 | 98 | /*! Create a list of instruction from string input. 99 | 100 | This function accepts a string, and a list of functions which can 101 | construct an Instruction, creating a list of correct instructions and 102 | slots from the string. The factories list must contain functions which can 103 | construct a function. The string is parsed by splitting on newlines, and 104 | attempting to match each line to an Instruction generated in the order of 105 | the factories list. 106 | 107 | E.g. 108 | input = "mov r0, r1\nadd r1, r2" 109 | factories = {functions to generate mov_Instruction and add_Instruction} 110 | 111 | // after parseInstructionList has been called: 112 | 113 | insns = {pointer to mov_Instruction, pointer to add_Instruction} 114 | slots = {pointer to RegisterSlot * 4} 115 | 116 | @param input The input string to parse 117 | @param factories A list of functions, which return a pointer to a newly 118 | allocated Instruction. 119 | @param insns The list in which the instructions will be returned. 120 | @param slots The list in which the corresponding slots will be 121 | returned. 122 | @return Whether or not the input string could be parsed 123 | without errors. 124 | 125 | */ 126 | bool parseInstructionList(std::string input, std::vector> factories, 127 | std::vector &insns, std::vector &slots); 128 | 129 | #endif 130 | -------------------------------------------------------------------------------- /tests/avr_instruction.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_DYN_LINK 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "algorithms/canonicalIterator.hpp" 11 | #include "algorithms/test.hpp" 12 | #include "frontends/avr.hpp" 13 | 14 | using namespace std; 15 | 16 | BOOST_AUTO_TEST_SUITE(avr_instruction_test) 17 | 18 | BOOST_AUTO_TEST_CASE( instruction_tests ) 19 | { 20 | AvrMachine mach, mach_expected; 21 | Instruction *insn; 22 | 23 | insn = new Avr_add(); 24 | auto slots = insn->getSlots(); 25 | slots[0]->setValue(0); 26 | slots[1]->setValue(0); 27 | 28 | mach.setRegisterValue(0, 0xA); 29 | insn->execute(&mach, &slots[0]); 30 | BOOST_REQUIRE(mach.getRegisterValue(0) == 0xA*2); 31 | 32 | mach.setRegisterValue(0, 0xF0); 33 | insn->execute(&mach, &slots[0]); 34 | BOOST_REQUIRE(mach.getRegisterValue(0) == ((0xF0*2)&0xFF)); 35 | 36 | mach_expected.setRegisterValue(0, ((0xF0*2)&0xFF)); 37 | BOOST_REQUIRE(mach_expected.equivalentState(mach) == true); 38 | 39 | //////////////////////////////////////////////////////////// 40 | } 41 | 42 | BOOST_AUTO_TEST_CASE( adc_test_1 ) 43 | { 44 | AvrMachine mach, mach_expected; 45 | auto insn = new Avr_adc(); 46 | auto slots = insn->getSlots(); 47 | slots[0]->setValue(0); 48 | slots[1]->setValue(0); 49 | 50 | mach.setRegisterValue(0, 0x10); 51 | insn->execute(&mach, &slots[0]); 52 | BOOST_CHECK(mach.getRegisterValue(0) == 0x20); 53 | } 54 | 55 | BOOST_AUTO_TEST_CASE( adc_test_2 ) 56 | { 57 | AvrMachine mach, mach_expected; 58 | auto insn = new Avr_adc(); 59 | auto slots = insn->getSlots(); 60 | slots[0]->setValue(0); 61 | slots[1]->setValue(0); 62 | 63 | mach.setRegisterValue(0, 0x10); 64 | mach.setFlagValue(AvrRegisterSlot::C, 1); 65 | insn->execute(&mach, &slots[0]); 66 | BOOST_CHECK(mach.getRegisterValue(0) == 0x21); 67 | } 68 | 69 | // Check the flags 70 | BOOST_AUTO_TEST_CASE( add_test_1 ) 71 | { 72 | AvrMachine mach, mach_expected; 73 | auto insn = new Avr_add(); 74 | auto slots = insn->getSlots(); 75 | slots[0]->setValue(0); 76 | slots[1]->setValue(0); 77 | 78 | mach.setRegisterValue(0, 0x90); 79 | mach.setFlagValue(AvrRegisterSlot::C, 0); 80 | insn->execute(&mach, &slots[0]); 81 | BOOST_CHECK(mach.getRegisterValue(0) == 0x20); 82 | BOOST_CHECK(mach.getFlagValue(AvrRegisterSlot::C) == 1); 83 | BOOST_CHECK(mach.getFlagValue(AvrRegisterSlot::V) == 1); 84 | } 85 | 86 | BOOST_AUTO_TEST_CASE( add_test_2 ) 87 | { 88 | AvrMachine mach, mach_expected; 89 | auto insn = new Avr_add(); 90 | auto slots = insn->getSlots(); 91 | slots[0]->setValue(0); 92 | slots[1]->setValue(0); 93 | 94 | mach.setRegisterValue(0, 0xC0); 95 | mach.setFlagValue(AvrRegisterSlot::C, 0); 96 | insn->execute(&mach, &slots[0]); 97 | BOOST_CHECK(mach.getRegisterValue(0) == 0x80); 98 | BOOST_CHECK(mach.getFlagValue(AvrRegisterSlot::C) == 1); 99 | BOOST_CHECK(mach.getFlagValue(AvrRegisterSlot::V) == 0); 100 | } 101 | 102 | BOOST_AUTO_TEST_CASE( adiw_test ) 103 | { 104 | AvrMachine mach, mach_expected; 105 | auto insn = new Avr_adiw(); 106 | auto slots = insn->getSlots(); 107 | slots[0]->setValue(24); 108 | slots[1]->setValue(0x18); 109 | 110 | mach.setRegisterValue(24, 0xF0); 111 | mach.setRegisterValue(25, 0x10); 112 | insn->execute(&mach, &slots[0]); 113 | BOOST_CHECK(mach.getRegisterValue(24) == 0x08); 114 | BOOST_CHECK(mach.getRegisterValue(25) == 0x11); 115 | } 116 | 117 | BOOST_AUTO_TEST_CASE( adiw_state_test ) 118 | { 119 | AvrMachine mach, mach_expected; 120 | auto insn = new Avr_adiw(); 121 | auto slots = insn->getSlots(); 122 | 123 | vector insns; 124 | insns.push_back(insn); 125 | 126 | slots[0]->setValue(24); 127 | slots[1]->setValue(0x18); 128 | 129 | mach.setRegisterValue(24, 0xF0); 130 | mach.setRegisterValue(25, 0x10); 131 | 132 | mach_expected.setRegisterValue(24, 0x08); 133 | mach_expected.setRegisterValue(25, 0x11); 134 | BOOST_CHECK(testEquivalence(insns, slots, mach, mach_expected) == true); 135 | } 136 | 137 | BOOST_AUTO_TEST_CASE( adiw_lambda_test ) 138 | { 139 | AvrMachine mach, mach_expected; 140 | 141 | vector insns; 142 | insns.push_back(new Avr_movw()); 143 | insns.push_back(new Avr_adiw()); 144 | 145 | auto slots = insns[0]->getSlots(); 146 | auto s2 = insns[1]->getSlots(); 147 | slots.insert(slots.end(), s2.begin(), s2.end()); 148 | 149 | function goal( 150 | [](AvrMachine &mach){ 151 | uint16_t tmp = (mach.getRegisterValue(1) << 8) | mach.getRegisterValue(0); 152 | tmp += 0x10; 153 | 154 | mach.setRegisterValue(0, tmp & 0xFF); 155 | mach.setRegisterValue(1, (tmp >> 8) & 0xFF); 156 | } 157 | ); 158 | 159 | // movw r24, r0 160 | slots[0]->setValue(24); 161 | slots[1]->setValue(0); 162 | // adiw r24, 0x10 163 | slots[2]->setValue(24); 164 | slots[3]->setValue(0x10); 165 | 166 | mach.setRegisterValue(0, 0xAB); 167 | mach.setRegisterValue(1, 0xCD); 168 | 169 | mach_expected = mach; 170 | goal(mach_expected); 171 | 172 | BOOST_CHECK(testEquivalence(insns, slots, mach, mach_expected) == true); 173 | 174 | // BOOST_CHECK(testEquivalence(insns, slots, mach, goal) == true); 175 | } 176 | 177 | BOOST_AUTO_TEST_CASE( machine_tests ) 178 | { 179 | AvrMachine mach, mach2; 180 | 181 | mach.setRegisterValue(0, 0xFF); 182 | BOOST_REQUIRE(mach.getRegisterValue(0) == 0xFF); 183 | 184 | mach2.setRegisterValue(0, 0xFF); 185 | BOOST_REQUIRE(mach == mach2); 186 | BOOST_REQUIRE(mach.equivalentState(mach2) == true); 187 | 188 | mach2.setRegisterValue(1, 0xAA); 189 | BOOST_REQUIRE(!(mach == mach2)); 190 | BOOST_REQUIRE(mach.equivalentState(mach2) == true); 191 | 192 | mach.setRegisterValue(1, 0xAB); 193 | BOOST_REQUIRE(mach.equivalentState(mach2) == false); 194 | 195 | } 196 | 197 | 198 | BOOST_AUTO_TEST_CASE( machine_permutation_tests ) 199 | { 200 | { 201 | AvrMachine mach, mach2; 202 | 203 | mach.setRegisterValue(0, 0xFF); 204 | mach2.setRegisterValue(1,0xFF); 205 | BOOST_REQUIRE(mach.containsState(mach2) == true); 206 | } 207 | 208 | { 209 | AvrMachine mach, mach2; 210 | mach.setRegisterValue(1, 0xAB); 211 | mach2.setRegisterValue(0, 0xAB); 212 | BOOST_REQUIRE(mach.containsState(mach2) == true); 213 | } 214 | 215 | { 216 | AvrMachine mach, mach2; 217 | mach.setRegisterValue(4, 0x12); 218 | mach2.setRegisterValue(3, 0x12); 219 | BOOST_REQUIRE(mach.containsState(mach2) == true); 220 | } 221 | 222 | { 223 | AvrMachine mach, mach2; 224 | mach.setRegisterValue(4, 0x12); 225 | mach2.setRegisterValue(3, 0x11); 226 | BOOST_REQUIRE(mach.containsState(mach2) == false); 227 | } 228 | 229 | { 230 | AvrMachine mach, mach2; 231 | mach.setRegisterValue(0, 0xAB); 232 | mach.setRegisterValue(1, 0xCD); 233 | mach2.setRegisterValue(24, 0xAB); 234 | mach2.setRegisterValue(25, 0xCD); 235 | BOOST_REQUIRE(mach.containsState(mach2) == true); 236 | } 237 | } 238 | 239 | BOOST_AUTO_TEST_SUITE_END() 240 | -------------------------------------------------------------------------------- /tests/bruteforce.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_DYN_LINK 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include "algorithms/bruteforce.hpp" 8 | #include "algorithms/canonicalIterator.hpp" 9 | 10 | using namespace std; 11 | 12 | BOOST_AUTO_TEST_SUITE(bruteforce_test) 13 | 14 | BOOST_AUTO_TEST_CASE( standard_tests ) 15 | { 16 | { 17 | vector values = {0,1}; 18 | vector::iterator> indices; 19 | 20 | indices.push_back(values.begin()); 21 | indices.push_back(values.begin()); 22 | 23 | BOOST_REQUIRE(*indices[0] == 0 && *indices[1] == 0); 24 | bruteforceIterate(values, indices); 25 | BOOST_REQUIRE(*indices[0] == 0 && *indices[1] == 1); 26 | bruteforceIterate(values, indices); 27 | BOOST_REQUIRE(*indices[0] == 1 && *indices[1] == 0); 28 | bruteforceIterate(values, indices); 29 | BOOST_REQUIRE(*indices[0] == 1 && *indices[1] == 1); 30 | } 31 | 32 | { 33 | vector values = {5,2,6}; 34 | vector::iterator> indices; 35 | 36 | indices.push_back(values.begin()); 37 | indices.push_back(values.begin()); 38 | indices.push_back(values.begin()); 39 | 40 | BOOST_REQUIRE(*indices[0] == 5 && *indices[1] == 5 && *indices[2] == 5); 41 | bruteforceIterate(values, indices); 42 | BOOST_REQUIRE(*indices[0] == 5 && *indices[1] == 5 && *indices[2] == 2); 43 | bruteforceIterate(values, indices); 44 | BOOST_REQUIRE(*indices[0] == 5 && *indices[1] == 5 && *indices[2] == 6); 45 | bruteforceIterate(values, indices); 46 | 47 | BOOST_REQUIRE(*indices[0] == 5 && *indices[1] == 2 && *indices[2] == 5); 48 | bruteforceIterate(values, indices); 49 | BOOST_REQUIRE(*indices[0] == 5 && *indices[1] == 2 && *indices[2] == 2); 50 | bruteforceIterate(values, indices); 51 | BOOST_REQUIRE(*indices[0] == 5 && *indices[1] == 2 && *indices[2] == 6); 52 | bruteforceIterate(values, indices); 53 | 54 | BOOST_REQUIRE(*indices[0] == 5 && *indices[1] == 6 && *indices[2] == 5); 55 | bruteforceIterate(values, indices); 56 | BOOST_REQUIRE(*indices[0] == 5 && *indices[1] == 6 && *indices[2] == 2); 57 | bruteforceIterate(values, indices); 58 | BOOST_REQUIRE(*indices[0] == 5 && *indices[1] == 6 && *indices[2] == 6); 59 | bruteforceIterate(values, indices); 60 | 61 | BOOST_REQUIRE(*indices[0] == 2 && *indices[1] == 5 && *indices[2] == 5); 62 | bruteforceIterate(values, indices); 63 | BOOST_REQUIRE(*indices[0] == 2 && *indices[1] == 5 && *indices[2] == 2); 64 | bruteforceIterate(values, indices); 65 | BOOST_REQUIRE(*indices[0] == 2 && *indices[1] == 5 && *indices[2] == 6); 66 | bruteforceIterate(values, indices); 67 | } 68 | 69 | { 70 | vector values = {0,1,2,3}; 71 | vector::iterator> indices; 72 | 73 | indices.push_back(values.begin()); 74 | indices.push_back(values.begin()); 75 | indices.push_back(values.begin()); 76 | indices.push_back(values.begin()); 77 | 78 | unsigned count = 0; 79 | 80 | do { 81 | count++; 82 | } while(bruteforceIterate(values, indices)); 83 | 84 | BOOST_REQUIRE(count == 4*4*4*4); 85 | } 86 | 87 | { 88 | vector values = {3,2,6,4,7,1}; 89 | vector::iterator> indices; 90 | 91 | indices.push_back(values.begin()); 92 | indices.push_back(values.begin()); 93 | indices.push_back(values.begin()); 94 | indices.push_back(values.begin()); 95 | indices.push_back(values.begin()); 96 | 97 | unsigned count = 0; 98 | 99 | do { 100 | count++; 101 | } while(bruteforceIterate(values, indices)); 102 | 103 | BOOST_REQUIRE(count == 6*6*6*6*6); 104 | } 105 | } 106 | 107 | 108 | BOOST_AUTO_TEST_CASE( custom_tests ) 109 | { 110 | { 111 | vector> values = {{0,1}, {0,1,2}}; 112 | vector::iterator> indices; 113 | 114 | indices.push_back(values[0].begin()); 115 | indices.push_back(values[1].begin()); 116 | 117 | BOOST_REQUIRE(*indices[0] == 0 && *indices[1] == 0); 118 | bruteforceIterate(values, indices); 119 | BOOST_REQUIRE(*indices[0] == 0 && *indices[1] == 1); 120 | bruteforceIterate(values, indices); 121 | BOOST_REQUIRE(*indices[0] == 0 && *indices[1] == 2); 122 | bruteforceIterate(values, indices); 123 | 124 | BOOST_REQUIRE(*indices[0] == 1 && *indices[1] == 0); 125 | bruteforceIterate(values, indices); 126 | BOOST_REQUIRE(*indices[0] == 1 && *indices[1] == 1); 127 | bruteforceIterate(values, indices); 128 | BOOST_REQUIRE(*indices[0] == 1 && *indices[1] == 2); 129 | bruteforceIterate(values, indices); 130 | BOOST_REQUIRE(*indices[0] == 0 && *indices[1] == 0); 131 | } 132 | 133 | { 134 | vector> values = {{0,0}, {0,0,0}, {0,0,0,0}, {0}}; 135 | vector::iterator> indices; 136 | 137 | indices.push_back(values[0].begin()); 138 | indices.push_back(values[1].begin()); 139 | indices.push_back(values[2].begin()); 140 | indices.push_back(values[3].begin()); 141 | 142 | unsigned count = 0; 143 | 144 | do { 145 | count++; 146 | } while(bruteforceIterate(values, indices)); 147 | 148 | BOOST_REQUIRE(count == 2*3*4*1); 149 | } 150 | } 151 | 152 | BOOST_AUTO_TEST_CASE( next_tests ) 153 | { 154 | { 155 | vector> multi_slots = {{new RegisterSlot(), new RegisterSlot()}, 156 | {new RegisterSlot(), new RegisterSlot()}}; 157 | 158 | vector c_iters = {canonicalIteratorBasic(multi_slots[0]), 159 | canonicalIteratorBasic(multi_slots[1])}; 160 | 161 | for(auto slots: multi_slots) 162 | for(auto slot: slots) 163 | slot->reset(); 164 | 165 | BOOST_REQUIRE(multi_slots[0][0]->getValue() == 0); 166 | BOOST_REQUIRE(multi_slots[0][1]->getValue() == 0); 167 | BOOST_REQUIRE(multi_slots[1][0]->getValue() == 0); 168 | BOOST_REQUIRE(multi_slots[1][1]->getValue() == 0); 169 | 170 | bruteforceIterate(c_iters); 171 | BOOST_REQUIRE(multi_slots[0][0]->getValue() == 0); 172 | BOOST_REQUIRE(multi_slots[0][1]->getValue() == 0); 173 | BOOST_REQUIRE(multi_slots[1][0]->getValue() == 0); 174 | BOOST_REQUIRE(multi_slots[1][1]->getValue() == 1); 175 | 176 | bruteforceIterate(c_iters); 177 | BOOST_REQUIRE(multi_slots[0][0]->getValue() == 0); 178 | BOOST_REQUIRE(multi_slots[0][1]->getValue() == 1); 179 | BOOST_REQUIRE(multi_slots[1][0]->getValue() == 0); 180 | BOOST_REQUIRE(multi_slots[1][1]->getValue() == 0); 181 | 182 | bruteforceIterate(c_iters); 183 | BOOST_REQUIRE(multi_slots[0][0]->getValue() == 0); 184 | BOOST_REQUIRE(multi_slots[0][1]->getValue() == 1); 185 | BOOST_REQUIRE(multi_slots[1][0]->getValue() == 0); 186 | BOOST_REQUIRE(multi_slots[1][1]->getValue() == 1); 187 | bruteforceIterate(c_iters); 188 | 189 | BOOST_REQUIRE(multi_slots[0][0]->getValue() == 0); 190 | BOOST_REQUIRE(multi_slots[0][1]->getValue() == 0); 191 | BOOST_REQUIRE(multi_slots[1][0]->getValue() == 0); 192 | BOOST_REQUIRE(multi_slots[1][1]->getValue() == 0); 193 | } 194 | 195 | { 196 | vector> multi_slots = { 197 | {new RegisterSlot(), new RegisterSlot(), new RegisterSlot()}, 198 | {new RegisterSlot(), new RegisterSlot(), new RegisterSlot()}, 199 | {new RegisterSlot(), new RegisterSlot(), new RegisterSlot()} 200 | }; 201 | 202 | vector c_iters = {canonicalIteratorBasic(multi_slots[0]), 203 | canonicalIteratorBasic(multi_slots[1]), canonicalIteratorBasic(multi_slots[2])}; 204 | 205 | for(auto slots: multi_slots) 206 | for(auto slot: slots) 207 | slot->reset(); 208 | 209 | unsigned count = 0; 210 | 211 | do { 212 | count++; 213 | } while(bruteforceIterate(c_iters)); 214 | 215 | BOOST_REQUIRE(count == 5*5*5); 216 | } 217 | } 218 | 219 | BOOST_AUTO_TEST_SUITE_END() 220 | -------------------------------------------------------------------------------- /tests/bruteforceByCost.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_DYN_LINK 2 | #include 3 | 4 | #include 5 | 6 | #include "algorithms/bruteforceByCost.hpp" 7 | 8 | using namespace std; 9 | 10 | BOOST_AUTO_TEST_SUITE(canonical_test); 11 | 12 | template 13 | void testBFBC(vector> values, vector::iterator> iters, 14 | function< C(vector::iterator>&)> costFn) 15 | { 16 | bruteforceByCost,C> bfbc(values, iters, costFn); 17 | 18 | uint64_t totalsize=1; 19 | uint64_t count=0; 20 | 21 | set::iterator>> results; 22 | 23 | for(auto &c: values) 24 | totalsize *= c.size(); 25 | 26 | do { 27 | count++; 28 | results.insert(iters); 29 | } while(bfbc.next()); 30 | 31 | BOOST_REQUIRE(count == totalsize); 32 | BOOST_REQUIRE(results.size() == totalsize); 33 | } 34 | 35 | BOOST_AUTO_TEST_CASE( general_test_1 ) 36 | { 37 | vector> vals = {{0,1,2,3},{0,1,2,3}}; 38 | vector::iterator> iters; 39 | 40 | testBFBC(vals, iters, 41 | [] (vector::iterator> &its) -> int 42 | { 43 | int i = 1; 44 | 45 | for(auto &k: its) 46 | i *= *k; 47 | return i; 48 | }); 49 | } 50 | 51 | 52 | BOOST_AUTO_TEST_CASE( general_test_2) 53 | { 54 | vector> vals = {{0,1,2,3},{0,1,2,3},{0,1,2,3},{0,1,2,3}}; 55 | vector::iterator> iters; 56 | 57 | testBFBC(vals, iters, 58 | [] (vector::iterator> &its) -> int 59 | { 60 | int i = 1; 61 | 62 | for(auto &k: its) 63 | i *= *k; 64 | return i; 65 | }); 66 | } 67 | 68 | BOOST_AUTO_TEST_CASE( general_test_3) 69 | { 70 | vector> vals = {{0,1,2,3,4,5},{0,1,2,3,4,5}}; 71 | vector::iterator> iters; 72 | 73 | 74 | testBFBC(vals, iters, 75 | [] (vector::iterator> &its) -> int 76 | { 77 | int i = (*its[0]-3) * (*its[0]-3) + (*its[1]-3)*(*its[1]-3); 78 | return i; 79 | }); 80 | } 81 | 82 | BOOST_AUTO_TEST_SUITE_END() 83 | -------------------------------------------------------------------------------- /tests/canonical_speed.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "algorithms/canonicalIterator.hpp" 9 | 10 | using namespace std; 11 | 12 | int main(int argc, char *argv[]) 13 | { 14 | if(argc < 3) 15 | { 16 | cout << "Usage:\n\tcanonical_speed N_SLOTS N_TESTS [MAXREG] [NLIVE]\n"; 17 | return 1; 18 | } 19 | 20 | unsigned n_tests = stoi(argv[2]); 21 | unsigned n_slots = stoi(argv[1]); 22 | 23 | unsigned max_n = n_slots; 24 | if(argc > 3) 25 | max_n = stoi(argv[3]); 26 | unsigned n_live = 2; 27 | if(argc > 4) 28 | n_live = stoi(argv[4]); 29 | 30 | vector slots; 31 | clock_t start, end; 32 | vector vals; 33 | 34 | for(unsigned i = 0; i < max_n; ++i) 35 | vals.push_back(i); 36 | 37 | for(unsigned i = 0; i < n_slots; ++i) 38 | { 39 | RegisterSlot *rs = new RegisterSlot(); 40 | 41 | rs->setValidArguments(vals); 42 | rs->setValue(0); 43 | rs->setRegisterClassID(0); 44 | slots.push_back(rs); 45 | } 46 | 47 | cout << "Starting nextCanonicalLiveness speed test... " << flush; 48 | start = clock(); 49 | canonicalIteratorLiveness c_iter_live(slots, n_live); 50 | for(unsigned i = 0; i < n_tests; ++i) 51 | { 52 | c_iter_live.next(); 53 | } 54 | end = clock(); 55 | 56 | double first_time = (end - start) / (double) CLOCKS_PER_SEC; 57 | cout << first_time << endl; 58 | 59 | for(auto p: slots) 60 | cout << p->getValue() << " "; 61 | cout << "\n\t"; 62 | 63 | for(unsigned i = 0; i < n_slots; ++i) 64 | { 65 | slots[i]->setValue(0); 66 | } 67 | 68 | cout << "Starting nextCanonical speed test... " << flush; 69 | start = clock(); 70 | canonicalIteratorGeneric c_iter(slots); 71 | for(unsigned i = 0; i < n_tests; ++i) 72 | { 73 | c_iter.next(); 74 | } 75 | end = clock(); 76 | 77 | double second_time = (end - start) / (double) CLOCKS_PER_SEC; 78 | cout << second_time << endl; 79 | 80 | for(auto p: slots) 81 | cout << p->getValue() << " "; 82 | cout << "\n\t"; 83 | 84 | for(unsigned i = 0; i < n_slots; ++i) 85 | { 86 | slots[i]->setValue(0); 87 | } 88 | 89 | cout << "Starting nextCanonicalBasic speed test... " << flush; 90 | start = clock(); 91 | canonicalIteratorBasic c_iter_basic(slots); 92 | for(unsigned i = 0; i < n_tests; ++i) 93 | { 94 | c_iter_basic.next(); 95 | } 96 | end = clock(); 97 | 98 | double third_time = (end - start) / (double) CLOCKS_PER_SEC; 99 | cout << third_time << endl; 100 | 101 | for(auto p: slots) 102 | cout << p->getValue() << " "; 103 | cout << "\n\t"; 104 | 105 | 106 | cout << "Basic is " << second_time/third_time << " times faster." << endl; 107 | cout << "Basic is " << first_time/third_time << " times faster than liveness." << endl; 108 | 109 | return 0; 110 | } 111 | -------------------------------------------------------------------------------- /tests/canonical_speed_full.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "algorithms/canonicalIterator.hpp" 9 | #include "algorithms/bruteforce.hpp" 10 | 11 | using namespace std; 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | if(argc < 2) 16 | { 17 | cout << "Usage:\n\tcanonical_speed N_SLOTS [MAXREG] [MODIFIERS NLIVE]\n"; 18 | return 1; 19 | } 20 | 21 | unsigned n_slots = stoi(argv[1]); 22 | 23 | unsigned max_n = n_slots; 24 | if(argc > 2) 25 | max_n = stoi(argv[2]); 26 | unsigned n_live = 2; 27 | string modifier; 28 | if(argc > 4) 29 | { 30 | modifier = argv[3]; 31 | n_live = stoi(argv[4]); 32 | if(modifier.size() != n_slots) 33 | { 34 | cout << "The number of characters in the modifier should be equal to the number of slots\n"; 35 | return 1; 36 | } 37 | } 38 | 39 | vector slots; 40 | clock_t start, end; 41 | vector vals; 42 | 43 | for(unsigned i = 0; i < max_n; ++i) 44 | vals.push_back(i); 45 | 46 | for(unsigned i = 0; i < n_slots; ++i) 47 | { 48 | RegisterSlot *rs = new RegisterSlot(modifier[i] == 'w', modifier[i] == 'r'); 49 | 50 | rs->setValidArguments(vals); 51 | rs->setValue(0); 52 | rs->setRegisterClassID(0); 53 | slots.push_back(rs); 54 | } 55 | 56 | unsigned n_tests_live=0, n_tests=0, n_tests_basic=0, n_tests_bruteforce=0; 57 | 58 | cout << "Starting nextCanonicalLiveness speed test... " << flush; 59 | start = clock(); 60 | canonicalIteratorLiveness c_iter_live(slots, n_live); 61 | 62 | while(c_iter_live.next()) 63 | n_tests_live++; 64 | 65 | end = clock(); 66 | 67 | double first_time = (end - start) / (double) CLOCKS_PER_SEC; 68 | cout << first_time << endl; 69 | 70 | for(unsigned i = 0; i < n_slots; ++i) 71 | { 72 | slots[i]->setValue(0); 73 | } 74 | 75 | cout << "Starting nextCanonical speed test... " << flush; 76 | start = clock(); 77 | canonicalIteratorGeneric c_iter(slots); 78 | while(c_iter.next()) 79 | n_tests++; 80 | end = clock(); 81 | 82 | double second_time = (end - start) / (double) CLOCKS_PER_SEC; 83 | cout << second_time << endl; 84 | 85 | for(unsigned i = 0; i < n_slots; ++i) 86 | { 87 | slots[i]->setValue(0); 88 | } 89 | 90 | cout << "Starting nextCanonicalBasic speed test... " << flush; 91 | start = clock(); 92 | canonicalIteratorBasic c_iter_basic(slots); 93 | while(c_iter_basic.next()) 94 | n_tests_basic++; 95 | end = clock(); 96 | 97 | double third_time = (end - start) / (double) CLOCKS_PER_SEC; 98 | cout << third_time << endl; 99 | 100 | cout << "Starting bruteforce tests... " << flush; 101 | vector::iterator> indices; 102 | 103 | for(unsigned i = 0; i < n_slots; ++i) 104 | { 105 | indices.push_back(vals.begin()); 106 | } 107 | 108 | start = clock(); 109 | while(bruteforceIterate(vals, indices)) 110 | n_tests_bruteforce++; 111 | end = clock(); 112 | 113 | double fourth_time = (end - start) / (double) CLOCKS_PER_SEC; 114 | cout << fourth_time << endl; 115 | 116 | cout << "Speed ups:\n"; 117 | cout << " Live vs bruteforce: " << fourth_time/first_time << endl; 118 | cout << " Normal vs bruteforce: " << fourth_time/second_time << endl; 119 | cout << " Basic vs bruteforce: " << fourth_time/third_time << endl; 120 | 121 | cout << "Number of tests:\n"; 122 | cout << "Live: " << n_tests_live << endl; 123 | cout << "Normal: " << n_tests << endl; 124 | cout << "Basic: " << n_tests_basic << endl; 125 | cout << "Brute: " << n_tests_bruteforce << endl; 126 | 127 | return 0; 128 | } 129 | -------------------------------------------------------------------------------- /tests/data/standard_1.csv: -------------------------------------------------------------------------------- 1 | 16 2 | 0, 0, 0, 0 3 | 0, 0, 0, 1 4 | 0, 0, 1, 0 5 | 0, 0, 1, 1 6 | 0, 0, 1, 2 7 | 0, 1, 0, 0 8 | 0, 1, 0, 1 9 | 0, 1, 0, 2 10 | 0, 1, 1, 0 11 | 0, 1, 1, 1 12 | 0, 1, 1, 2 13 | 0, 1, 2, 0 14 | 0, 1, 2, 1 15 | 0, 1, 2, 2 16 | 0, 1, 2, 3 17 | 0, 0, 0, 0 18 | -------------------------------------------------------------------------------- /tests/frontend.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_DYN_LINK 2 | #include 3 | 4 | #include "frontend.hpp" 5 | 6 | BOOST_AUTO_TEST_SUITE(frontend_test) 7 | 8 | BOOST_AUTO_TEST_CASE( target_machine_register_test ) 9 | { 10 | TargetMachine test_mach, expected_mach; 11 | 12 | for(int i = 0; i < 8; ++i) 13 | BOOST_CHECK(test_mach.getRegisterValue(i) == 0); 14 | 15 | BOOST_CHECK(test_mach.equivalentState(expected_mach) == true); 16 | 17 | test_mach.setRegisterValue(0, 0xFFFFFFFF); 18 | BOOST_CHECK(test_mach.getRegisterValue(0) == 0xFFFFFFFF); 19 | for(int i = 1; i < 8; ++i) 20 | BOOST_CHECK(test_mach.getRegisterValue(i) == 0); 21 | 22 | BOOST_CHECK(test_mach.equivalentState(expected_mach) == false); 23 | } 24 | 25 | BOOST_AUTO_TEST_CASE( target_machine_containsState_test ) 26 | { 27 | TargetMachine test_mach, expected_mach; 28 | 29 | expected_mach.setRegisterValue(0, 0xFFFFFFFF); 30 | test_mach.setRegisterValue(0, 0xFFFFFFFF); 31 | 32 | BOOST_CHECK(test_mach.containsState(expected_mach) == true); 33 | 34 | test_mach.setRegisterValue(1, 0xFFFFFFFF); 35 | BOOST_CHECK(test_mach.containsState(expected_mach) == true); 36 | 37 | test_mach.setRegisterValue(0, 0x0); 38 | BOOST_CHECK(test_mach.containsState(expected_mach) == true); 39 | 40 | test_mach.setRegisterValue(1, 0x0); 41 | BOOST_CHECK(test_mach.containsState(expected_mach) == false); 42 | 43 | expected_mach.setRegisterValue(0, 0xF00DCAFE); 44 | expected_mach.setRegisterValue(2, 0xBEEFCAFE); 45 | test_mach.setRegisterValue(0, 0x1); 46 | test_mach.setRegisterValue(1, 0x2); 47 | test_mach.setRegisterValue(2, 0xF00DCAFE); 48 | test_mach.setRegisterValue(3, 0x4); 49 | test_mach.setRegisterValue(4, 0xBEEFCAFE); 50 | BOOST_CHECK(test_mach.containsState(expected_mach) == true); 51 | } 52 | 53 | BOOST_AUTO_TEST_SUITE_END() 54 | -------------------------------------------------------------------------------- /tests/slots.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_DYN_LINK 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include "slots.hpp" 8 | #include "algorithms/bruteforce.hpp" 9 | 10 | using namespace std; 11 | 12 | BOOST_AUTO_TEST_SUITE(slots_test) 13 | 14 | BOOST_AUTO_TEST_CASE( bruteforce_slot_tests ) 15 | { 16 | { 17 | vector values; 18 | 19 | values.push_back(ConstantSlot({{0,10}})); 20 | values.push_back(ConstantSlot({{0,10}})); 21 | 22 | values[0].reset(); 23 | values[1].reset(); 24 | 25 | unsigned count = 0; 26 | 27 | do { 28 | count++; 29 | } while(bruteforceIterate(values)); 30 | 31 | BOOST_REQUIRE(count == 11*11); 32 | } 33 | 34 | { 35 | vector values; 36 | 37 | values.push_back(ConstantSlot({{0,1}, {100,102}})); 38 | values.push_back(ConstantSlot({{0,2}, {5,6}})); 39 | 40 | values[0].reset(); 41 | values[1].reset(); 42 | 43 | BOOST_REQUIRE(values[0].getValue() == 0); 44 | BOOST_REQUIRE(values[1].getValue() == 0); 45 | 46 | bruteforceIterate(values); 47 | BOOST_REQUIRE(values[0].getValue() == 0); 48 | BOOST_REQUIRE(values[1].getValue() == 1); 49 | 50 | bruteforceIterate(values); 51 | BOOST_REQUIRE(values[0].getValue() == 0); 52 | BOOST_REQUIRE(values[1].getValue() == 2); 53 | 54 | bruteforceIterate(values); 55 | BOOST_REQUIRE(values[0].getValue() == 0); 56 | BOOST_REQUIRE(values[1].getValue() == 5); 57 | 58 | bruteforceIterate(values); 59 | BOOST_REQUIRE(values[0].getValue() == 0); 60 | BOOST_REQUIRE(values[1].getValue() == 6); 61 | 62 | bruteforceIterate(values); 63 | BOOST_REQUIRE(values[0].getValue() == 1); 64 | BOOST_REQUIRE(values[1].getValue() == 0); 65 | 66 | bruteforceIterate(values); 67 | BOOST_REQUIRE(values[0].getValue() == 1); 68 | BOOST_REQUIRE(values[1].getValue() == 1); 69 | 70 | bruteforceIterate(values); 71 | BOOST_REQUIRE(values[0].getValue() == 1); 72 | BOOST_REQUIRE(values[1].getValue() == 2); 73 | 74 | bruteforceIterate(values); 75 | BOOST_REQUIRE(values[0].getValue() == 1); 76 | BOOST_REQUIRE(values[1].getValue() == 5); 77 | 78 | bruteforceIterate(values); 79 | BOOST_REQUIRE(values[0].getValue() == 1); 80 | BOOST_REQUIRE(values[1].getValue() == 6); 81 | 82 | bruteforceIterate(values); 83 | BOOST_REQUIRE(values[0].getValue() == 100); 84 | BOOST_REQUIRE(values[1].getValue() == 0); 85 | } 86 | } 87 | 88 | BOOST_AUTO_TEST_SUITE_END() 89 | -------------------------------------------------------------------------------- /tests/test.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_DYN_LINK 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include "frontend.hpp" 8 | #include "algorithms/test.hpp" 9 | 10 | using namespace std; 11 | 12 | BOOST_AUTO_TEST_SUITE(test_algorithm_test) 13 | 14 | class TestMachine : public TargetMachine 15 | { 16 | public: 17 | TestMachine(vector regs_={0,0,0,0}) 18 | { 19 | for(int i = 0; i < 4; ++i) 20 | registers[i] = regs_[i]; 21 | } 22 | 23 | bool operator== (TestMachine &rhs) 24 | { 25 | for(int i = 0; i < 4; ++i) 26 | { 27 | if(registers[i] != rhs.registers[i]) 28 | return false; 29 | } 30 | return true; 31 | } 32 | }; 33 | 34 | class TestInstruction: public Instruction 35 | { 36 | public: 37 | TestInstruction(unsigned sum_slots_, unsigned add_) 38 | { 39 | sum_slots = sum_slots_; 40 | add_extra = add_; 41 | BOOST_REQUIRE(sum_slots > 0); 42 | } 43 | 44 | virtual unsigned execute(TargetMachineBase *_mach, Slot **slots) 45 | { 46 | TestMachine *mach = static_cast(_mach); 47 | uint32_t sum = 0; 48 | 49 | for(unsigned i = 0; i < sum_slots; ++i) 50 | { 51 | uint32_t reg = mach->getRegister(slots[i]); 52 | 53 | sum += reg; 54 | } 55 | 56 | sum += add_extra; 57 | 58 | mach->setRegister(slots[0], sum); 59 | 60 | return sum_slots; 61 | } 62 | 63 | virtual unsigned getNumberOfSlots() 64 | { 65 | return sum_slots; 66 | } 67 | 68 | unsigned sum_slots; 69 | unsigned add_extra; 70 | }; 71 | 72 | class TestInstructionMove: public Instruction 73 | { 74 | public: 75 | TestInstructionMove() 76 | { 77 | } 78 | 79 | virtual unsigned execute(TargetMachineBase *_mach, Slot **slots) 80 | { 81 | TestMachine *mach = static_cast(_mach); 82 | 83 | mach->setRegister(slots[0], mach->getRegister(slots[1])); 84 | 85 | return 2; 86 | } 87 | 88 | virtual unsigned getNumberOfSlots() 89 | { 90 | return 2; 91 | } 92 | }; 93 | 94 | BOOST_AUTO_TEST_CASE( machine_state_tests ) 95 | { 96 | { 97 | vector insns; 98 | vector slots; 99 | TestMachine mach_initial({0,0,0,0}); 100 | TestMachine mach_expected({0,0,0,0}); 101 | 102 | insns.push_back(new TestInstruction(1, 0)); 103 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 104 | mach_expected.setRegisterValue(0, 0); 105 | 106 | BOOST_REQUIRE(testEquivalence(insns,slots,mach_initial, mach_expected) == true); 107 | } 108 | 109 | { 110 | vector insns; 111 | vector slots; 112 | TestMachine mach_initial({1,2,0,0}); 113 | TestMachine mach_expected({3,2,0,0}); 114 | 115 | insns.push_back(new TestInstruction(2, 0)); 116 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 117 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 1)); 118 | mach_expected.setRegisterValue(0, 3); 119 | 120 | BOOST_REQUIRE(testEquivalence(insns,slots,mach_initial, mach_expected) == true); 121 | } 122 | 123 | { 124 | vector insns; 125 | vector slots; 126 | TestMachine mach_initial({1,2,0,0}); 127 | TestMachine mach_expected({3,5,0,0}); 128 | 129 | // sum r0, r1 130 | // sum r1, r0 131 | // Overall: r0 = r0 + r1, r1 = r0 + r1 + r1 132 | insns.push_back(new TestInstruction(2, 0)); 133 | insns.push_back(new TestInstruction(2, 0)); 134 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 135 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 1)); 136 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 1)); 137 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 138 | mach_expected.setRegisterValue(0, 3); 139 | mach_expected.setRegisterValue(1, 5); 140 | 141 | BOOST_REQUIRE(testEquivalence(insns,slots,mach_initial, mach_expected) == true); 142 | } 143 | } 144 | 145 | BOOST_AUTO_TEST_CASE( instruction_sequences_tests ) 146 | { 147 | srand(0); 148 | 149 | { 150 | vector insns; 151 | vector slots; 152 | vector ref_insns; 153 | vector ref_slots; 154 | 155 | // sum r0, r0 156 | insns.push_back(new TestInstruction(1, 0)); 157 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 158 | 159 | // sum r0, r0 160 | ref_insns.push_back(new TestInstruction(1, 0)); 161 | ref_slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 162 | 163 | BOOST_REQUIRE(testEquivalence(insns,slots,ref_insns,ref_slots) == true); 164 | BOOST_REQUIRE(testEquivalenceMultiple(insns,slots,ref_insns,ref_slots) == true); 165 | } 166 | 167 | { 168 | vector insns; 169 | vector slots; 170 | vector ref_insns; 171 | vector ref_slots; 172 | 173 | // sum r0, r0 174 | // sum r0, r0 175 | // Overall: r0 = r0 * 4 176 | insns.push_back(new TestInstruction(2, 0)); 177 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 178 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 179 | insns.push_back(new TestInstruction(2, 0)); 180 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 181 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 182 | 183 | // sum r0, r0, r0, r0 184 | // Overall: r0 = r0 * 4 185 | ref_insns.push_back(new TestInstruction(4, 0)); 186 | ref_slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 187 | ref_slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 188 | ref_slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 189 | ref_slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 190 | 191 | BOOST_REQUIRE(testEquivalence(insns,slots,ref_insns,ref_slots) == true); 192 | BOOST_REQUIRE(testEquivalenceMultiple(insns,slots,ref_insns,ref_slots) == true); 193 | } 194 | 195 | { 196 | vector insns; 197 | vector slots; 198 | vector ref_insns; 199 | vector ref_slots; 200 | 201 | // sum r0, r0 202 | // sum r0, r0 203 | // Overall: r0 = r0 * 4 204 | insns.push_back(new TestInstruction(2, 0)); 205 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 206 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 207 | insns.push_back(new TestInstruction(2, 0)); 208 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 209 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 210 | 211 | // sum r0, r0, r0, r0 212 | // Overall: r0 = r0 * 4 213 | ref_insns.push_back(new TestInstruction(4, 0)); 214 | ref_slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 215 | ref_slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 216 | ref_slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 217 | ref_slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 218 | 219 | BOOST_REQUIRE(testEquivalence(insns,slots,ref_insns,ref_slots) == true); 220 | BOOST_REQUIRE(testEquivalenceMultiple(insns,slots,ref_insns,ref_slots) == true); 221 | } 222 | 223 | { 224 | vector insns; 225 | vector slots; 226 | vector ref_insns; 227 | vector ref_slots; 228 | 229 | // sum r0, r0 230 | // move r1, r0 231 | // Overall: r0 = r1 * 2 232 | insns.push_back(new TestInstruction(2, 0)); 233 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 234 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 235 | insns.push_back(new TestInstructionMove()); 236 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 1)); 237 | slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 238 | 239 | // sum r0, r0 240 | // Overall: r0 = r0 * 2 241 | ref_insns.push_back(new TestInstruction(2, 0)); 242 | ref_slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 243 | ref_slots.push_back(new RegisterSlot(true, true, {0,1,2,3}, 0)); 244 | 245 | BOOST_REQUIRE(testEquivalence(insns,slots,ref_insns,ref_slots) == true); 246 | BOOST_REQUIRE(testEquivalenceMultiple(insns,slots,ref_insns,ref_slots) == true); 247 | } 248 | } 249 | 250 | BOOST_AUTO_TEST_SUITE_END() 251 | -------------------------------------------------------------------------------- /tests/test_main.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_DYN_LINK 2 | #define BOOST_TEST_MAIN 3 | #include 4 | -------------------------------------------------------------------------------- /tests/utility.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_DYN_LINK 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include "utility.hpp" 8 | 9 | using namespace std; 10 | 11 | BOOST_AUTO_TEST_SUITE(utility_test) 12 | 13 | BOOST_AUTO_TEST_CASE( combination_tests ) 14 | { 15 | { 16 | vector values = {0,1,2,3,4,5,6,7}; 17 | 18 | Combinations comb(values.size(), 4); 19 | 20 | unsigned count = 0; 21 | do { 22 | count++; 23 | } while(comb.next()); 24 | 25 | // 8 choose 4 26 | BOOST_CHECK(count == 70); 27 | } 28 | 29 | { 30 | vector values = {0,1,2,3,4,5}; 31 | 32 | Combinations comb(values.size(), 2); 33 | 34 | unsigned count = 0; 35 | do { 36 | count++; 37 | } while(comb.next()); 38 | 39 | // 6 choose 2 40 | BOOST_CHECK(count == 15); 41 | } 42 | 43 | { 44 | vector values = {0,1,2,3,4,5}; 45 | vector sel; 46 | 47 | Combinations comb(values.size(), 2); 48 | 49 | comb.getSelection(sel); 50 | BOOST_CHECK(sel == vector({0,1})); 51 | comb.next(); 52 | comb.getSelection(sel); 53 | BOOST_CHECK(sel == vector({0,2})); 54 | comb.next(); 55 | comb.getSelection(sel); 56 | BOOST_CHECK(sel == vector({1,2})); 57 | comb.next(); 58 | comb.getSelection(sel); 59 | BOOST_CHECK(sel == vector({0,3})); 60 | comb.next(); 61 | comb.getSelection(sel); 62 | BOOST_CHECK(sel == vector({1,3})); 63 | comb.next(); 64 | comb.getSelection(sel); 65 | BOOST_CHECK(sel == vector({2,3})); 66 | comb.next(); 67 | comb.getSelection(sel); 68 | BOOST_CHECK(sel == vector({0,4})); 69 | } 70 | } 71 | 72 | BOOST_AUTO_TEST_SUITE_END() 73 | --------------------------------------------------------------------------------